SSH-Infrastructure / .doc / ssh-jump-architecture.md
1 contributor
222 lines | 9.434kb

Arhitectura SSH Curenta

Acest document descrie configuratia activa din /home/nextgen/.ssh. Sursa versionata a proiectului este in /home/nextgen/projects/ssh-infrastructure; /home/nextgen/.ssh ramane runtime OpenSSH si nu contine repo-ul git. Ultima actualizare: 2026-05-15. Jurnalul istoric ssh-jump-attempts.md este obsolete si poate fi consultat doar din git.

Structura Locala

/home/nextgen/.ssh/
  config                        <- single-file generat din inventory/hosts.yaml
  known_hosts
  known_hosts.old
  authorized_keys
  keys/
    id_ed25519
    id_ed25519.pub
    elastix-root.pub
  .doc/
    ssh-jump-architecture.md

~/.local/bin/
  ssh
  scp
  sftp

Reguli:

  • Proiectul versionat sta in ~/projects/ssh-infrastructure; ~/.ssh ramane runtime OpenSSH.
  • Cheile de identitate stau in ~/.ssh/keys.
  • Hosturile SSH sunt definite in inventory/hosts.yaml, apoi generate in generated/*.conf.
  • ~/.ssh/config este instalat din generated/client.conf prin tools/deploy-local.sh; nu se editeaza manual.
  • Scripturile sursa stau versionate in scripts/ in repo.
  • ~/.local/bin/ contine copiile executabile instalate de tools/deploy-local.sh; nu se editeaza manual.
  • authorized_keys, known_hosts si config raman in radacina .ssh, pentru compatibilitate cu OpenSSH.
  • j1-relay.sh, ssh-proxy.sh, ensure-ssh-agent-bridge.sh si ensure-ssh-jump.sh au fost eliminate; ssh-wrapper.sh ruleaza clientul SSH activ pe is-jumper, unde se afla cheia fizica.

Wrappers locale

Scripturile sursa sunt in scripts/ in repo; ~/.local/bin/ contine copiile executabile instalate local.

Comanda Script Mecanism
ssh ssh-wrapper.sh parseaza args, rezolva hostul via ssh -G, construieste sesiunea nested
scp scp-wrapper.sh apeleaza /usr/bin/scp -S ~/.local/bin/ssh — rutarea e delegata wrapper-ului ssh
sftp sftp-wrapper.sh apeleaza /usr/bin/sftp -S ~/.local/bin/ssh — idem
  • Compatibilitatea SSH pentru hop-ul final este responsabilitatea serverelor J1/J2; wrapperele locale nu reproduc algoritmi, KEX, cipher-uri sau OPENSSL_CONF.
  • Daca PATH-ul include ~/.local/bin inaintea /usr/bin, comenzile ssh/scp/sftp folosesc automat aceste wrappers.

Arhitectura rețelei

192.168.2.0/24  — rețea locală de birou
  is-toltec  (workstation-ul local)
  is-jumper  192.168.2.100  (gardian cheie + client VPN)

10.253.51.0/24  — rețea internă companie (acces via VPN de pe is-jumper)
  J1  10.253.51.50:25904
  J2  10.253.51.52:25904
  hosturi finale (voip, porta, radius etc.)

is-jumper (192.168.2.100) este pe rețeaua locală de birou — accesibil direct din is-toltec, fără VPN. Este un client VPN (nu server): prin el se obține acces la 10.253.51.0/24. Este gardianul cheii fizice (card RSA 4096) deoarece deservește mai mulți utilizatori din 192.168.2.0/24.

Cheia fizică (cardul) este montată exclusiv pe is-jumper și expusă prin GPG agent la /run/user/0/gnupg/S.gpg-agent.ssh. Wrapper-ul nu mai forwardează acest socket pe mașina locală; în schimb intră pe is-jumper, setează SSH_AUTH_SOCK la socketul local de acolo și rulează de pe is-jumper clientul SSH către J1/J2/j1/j2.

Lanțul de acces

Calea standard (VPN activ, J1):

local
  -> is-jumper (192.168.2.100, executor SSH + cheie fizica)
  -> J1 (10.253.51.50:25904)
  -> host final

Calea publică (urgențe, fără rută VPN, j1/j2):

local
  -> is-jumper (192.168.2.100, executor SSH + cheie fizica)
  -> j1.next-gen.ro:25904
  -> host final

Sesiuni interactive pe J1/J2:

local -> is-jumper -> J1
local -> is-jumper -> J2

Nu mai exista bridge local de agent (/tmp/is-jumper-agent.sock). Cheia fizica ramane folosita local pe is-jumper.

Jumps disponibile via flaguri wrapper:

Flag Jump Rută Când
implicit / -J1 J1 (10.253.51.50) client SSH rulat pe is-jumper standard
-J2 J2 (10.253.51.52) client SSH rulat pe is-jumper failover VPN
-j1 j1.next-gen.ro client SSH rulat pe is-jumper urgențe
-j2 j2.next-gen.ro client SSH rulat pe is-jumper urgențe

Scripturi

ssh-wrapper.sh

Parseaza argumentele ssh, rezolva hostul via ssh -G, construieste sesiunea nested activa pe is-jumper:

exec /usr/bin/ssh is-jumper "SSH_AUTH_SOCK=/run/user/0/gnupg/S.gpg-agent.ssh ssh -A <jump_host> '<final_ssh_cmd>'"

Bypass automat (pass-through direct) pentru: - is-jumper / 192.168.2.100 - Flaguri de interogare: -G, -Q, -V, --help

Pentru J1/J2/j1/j2, wrapper-ul conecteaza intai local la is-jumper, apoi ruleaza acolo ssh -A cu SSH_AUTH_SOCK=/run/user/0/gnupg/S.gpg-agent.ssh. Pentru hosturile finale, comanda de pe jump ruleaza inca un ssh catre hostul final. Pentru scp/sftp, wrapper-ul pastreaza forma de subsystem -s ... sftp.

scp-wrapper.sh / sftp-wrapper.sh

Wrappers subtiri care injecteaza -S ~/.local/bin/ssh la apelul sistemului:

/usr/bin/scp -S ~/.local/bin/ssh "$@"
/usr/bin/sftp -S ~/.local/bin/ssh "$@"

Rutarea este delegata integral catre ssh-wrapper.sh; scp/sftp raman transparente pentru utilizator.

Nu mai exista scripturi active bazate pe Python, ProxyJump sau port-forwarding externe; vechiul helper Python a fost eliminat dupa ce a fost semnalat de Sentinel.

Config SSH

~/.ssh/config este un single-file generat din inventory/hosts.yaml:

# Generated by tools/generate-configs.py.
# Do not edit this file directly; edit inventory/hosts.yaml.

Generatorul produce:

Fisier Destinatie Rol
generated/client.conf client local config runtime pentru ~/.ssh/config
generated/is-jumper.conf is-jumper config pentru jump aliases
generated/j1.conf J1 hosturi finale
generated/j2.conf J2 hosturi finale

Reguli de configurare:

  • hosturile finale definesc doar HostName, User si Port;
  • pe client, hosturile importate din IFS folosesc drept HostName numele canonic deja cunoscut pe jump, iar IP-ul ramane alias pentru autocomplete;
  • is-jumper defineste si cheia locala de acces (IdentityFile, IdentitiesOnly);
  • wrapperul construieste ruta nested prin is-jumper -> J1 implicit;
  • optiunile comune per-grup (ConnectTimeout etc.) stau in inventory/hosts.yaml;
  • generated/j1.conf si generated/j2.conf mostenesc blocul global company-managed si omit User/Port cand toate aliasurile unui host sunt deja acoperite de regulile Match Host de pe jump;
  • generated/j1.conf si generated/j2.conf nu mai includ hosturile care folosesc doar defaulturi mostenite; raman doar override-urile efective si exceptiile per-pattern care trebuie pastrate pe jump;
  • generated/j1.conf si generated/j2.conf sunt generate fara comentarii, doar cu stanza-urile SSH necesare;
  • hosturile Radius folosesc acelasi flux nested prin J1 ca restul hosturilor finale.

Aliasuri principale:

Alias Rol Rutare
is-jumper VPN gateway + gardian cheie fizica direct (IP 192.168.2.100)
J1, J2 jump hosts, login interactiv wrapper prin is-jumper
voip-prov, voip-prov-root host VoIP provider wrapper nested prin J1
porta-sip, porta-web, porta-db, porta-configurator PortaOne MR30 wrapper nested prin J1
elastix host vechi wrapper nested prin J1
*.radius-db, *.radius-pppoe baze Radius regionale wrapper nested prin J1

J1 si J2 nu mai folosesc ProxyJump, IdentityAgent sau RemoteCommand in configul local; wrapper-ul orchestreaza explicit conexiunea prin is-jumper.

PortaOne

Aliasuri PortaOne:

  • porta-sip, p12-sip, p12, p12.voip.ro -> 193.16.148.4
  • porta-web, porta-api, porta-slave, porta7, telefonie.next-gen.ro -> 193.16.148.7
  • porta-db, porta-master, porta1 -> 193.16.148.11
  • porta-configurator, porta-config -> 193.16.148.13

Aceste hosturi folosesc ruta nested din wrapper; eventualele optiuni de compatibilitate ale hop-ului final sunt asigurate pe J1/J2.

Verificari

Verificare configuratie fara conectare:

ssh -G is-jumper | grep -E '^(hostname|user|identityfile|identitiesonly)'
ssh -G porta-db | grep -E '^(hostname|user|port)'
ssh -G falticeni.radius-db | grep -E '^(hostname|user|port|connecttimeout)'

Verificare read-only cu conectare:

ssh porta-db hostname
ssh porta-sip 'service porta-sip status'
ssh voip-prov hostname
scp porta-db:/etc/hosts /tmp/test-scp
sftp porta-db <<< 'ls /'

Mentenanta

  • Cand adaugi o cheie noua, pune-o in ~/.ssh/keys si seteaza permisiuni 600 pentru cheia privata.
  • Cand adaugi un host nou: adauga-l in inventory/hosts.yaml, ruleaza generatorul si apoi tools/deploy-local.sh.
  • Cand adaugi un domeniu nou: adauga un grup nou in inventory/hosts.yaml.
  • Cand adaugi un wrapper nou: adauga scriptul in scripts/ in repo si lasa tools/deploy-local.sh sa il instaleze in ~/.local/bin/.
  • Nu readuce ProxyJump, IdentityAgent /tmp/is-jumper-agent.sock, helperul Python sau port-forwarding per-host.
  • Nu activa ForwardAgent yes pe hosturile finale fara un motiv explicit.
  • Dupa modificari la wrappers sau config, verifica: ssh -G <alias> si cel putin un alias read-only (ssh porta-db hostname).