SSH-Infrastructure / .doc / ssh-jump-architecture.md
Newer Older
222 lines | 9.434kb
Bogdan Timofte authored 2 weeks ago
1
# Arhitectura SSH Curenta
2

            
3
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.
4

            
5
## Structura Locala
6

            
7
```text
8
/home/nextgen/.ssh/
9
  config                        <- single-file generat din inventory/hosts.yaml
10
  known_hosts
11
  known_hosts.old
12
  authorized_keys
13
  keys/
14
    id_ed25519
15
    id_ed25519.pub
16
    elastix-root.pub
17
  .doc/
18
    ssh-jump-architecture.md
19

            
20
~/.local/bin/
21
  ssh
22
  scp
23
  sftp
24
```
25

            
26
Reguli:
27

            
28
- Proiectul versionat sta in `~/projects/ssh-infrastructure`; `~/.ssh` ramane runtime OpenSSH.
29
- Cheile de identitate stau in `~/.ssh/keys`.
30
- Hosturile SSH sunt definite in `inventory/hosts.yaml`, apoi generate in `generated/*.conf`.
31
- `~/.ssh/config` este instalat din `generated/client.conf` prin `tools/deploy-local.sh`; nu se editeaza manual.
32
- Scripturile sursa stau versionate in `scripts/` in repo.
33
- `~/.local/bin/` contine copiile executabile instalate de `tools/deploy-local.sh`; nu se editeaza manual.
34
- `authorized_keys`, `known_hosts` si `config` raman in radacina `.ssh`, pentru compatibilitate cu OpenSSH.
35
- `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.
36

            
37
## Wrappers locale
38

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

            
41
| Comanda | Script | Mecanism |
42
| --- | --- | --- |
43
| `ssh` | `ssh-wrapper.sh` | parseaza args, rezolva hostul via `ssh -G`, construieste sesiunea nested |
44
| `scp` | `scp-wrapper.sh` | apeleaza `/usr/bin/scp -S ~/.local/bin/ssh` — rutarea e delegata wrapper-ului ssh |
45
| `sftp` | `sftp-wrapper.sh` | apeleaza `/usr/bin/sftp -S ~/.local/bin/ssh` — idem |
46

            
47
- Compatibilitatea SSH pentru hop-ul final este responsabilitatea serverelor `J1`/`J2`; wrapperele locale nu reproduc algoritmi, KEX, cipher-uri sau `OPENSSL_CONF`.
48
- Daca PATH-ul include `~/.local/bin` inaintea `/usr/bin`, comenzile `ssh`/`scp`/`sftp` folosesc automat aceste wrappers.
49

            
50
## Arhitectura rețelei
51

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

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

            
63
**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`.
64

            
65
**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.
66

            
67
## Lanțul de acces
68

            
69
Calea standard (VPN activ, J1):
70

            
71
```text
72
local
73
  -> is-jumper (192.168.2.100, executor SSH + cheie fizica)
74
  -> J1 (10.253.51.50:25904)
75
  -> host final
76
```
77

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

            
80
```text
81
local
82
  -> is-jumper (192.168.2.100, executor SSH + cheie fizica)
83
  -> j1.next-gen.ro:25904
84
  -> host final
85
```
86

            
87
Sesiuni interactive pe J1/J2:
88

            
89
```text
90
local -> is-jumper -> J1
91
local -> is-jumper -> J2
92
```
93

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

            
96
Jumps disponibile via flaguri wrapper:
97

            
98
| Flag | Jump | Rută | Când |
99
| --- | --- | --- | --- |
100
| implicit / `-J1` | J1 (10.253.51.50) | client SSH rulat pe is-jumper | standard |
101
| `-J2` | J2 (10.253.51.52) | client SSH rulat pe is-jumper | failover VPN |
102
| `-j1` | j1.next-gen.ro | client SSH rulat pe is-jumper | urgențe |
103
| `-j2` | j2.next-gen.ro | client SSH rulat pe is-jumper | urgențe |
104

            
105
## Scripturi
106

            
107
### ssh-wrapper.sh
108

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

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

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

            
119
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`.
120

            
121
### scp-wrapper.sh / sftp-wrapper.sh
122

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

            
125
```bash
126
/usr/bin/scp -S ~/.local/bin/ssh "$@"
127
/usr/bin/sftp -S ~/.local/bin/ssh "$@"
128
```
129

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

            
132
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.
133

            
134
## Config SSH
135

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

            
138
```sshconfig
139
# Generated by tools/generate-configs.py.
140
# Do not edit this file directly; edit inventory/hosts.yaml.
141
```
142

            
143
Generatorul produce:
144

            
145
| Fisier | Destinatie | Rol |
146
| --- | --- | --- |
147
| `generated/client.conf` | client local | config runtime pentru `~/.ssh/config` |
148
| `generated/is-jumper.conf` | is-jumper | config pentru jump aliases |
149
| `generated/j1.conf` | J1 | hosturi finale |
150
| `generated/j2.conf` | J2 | hosturi finale |
151

            
152
Reguli de configurare:
153

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

            
170
Aliasuri principale:
171

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

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

            
183
## PortaOne
184

            
185
Aliasuri PortaOne:
186

            
187
- `porta-sip`, `p12-sip`, `p12`, `p12.voip.ro` -> `193.16.148.4`
188
- `porta-web`, `porta-api`, `porta-slave`, `porta7`, `telefonie.next-gen.ro` -> `193.16.148.7`
189
- `porta-db`, `porta-master`, `porta1` -> `193.16.148.11`
190
- `porta-configurator`, `porta-config` -> `193.16.148.13`
191

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

            
194
## Verificari
195

            
196
Verificare configuratie fara conectare:
197

            
198
```bash
199
ssh -G is-jumper | grep -E '^(hostname|user|identityfile|identitiesonly)'
200
ssh -G porta-db | grep -E '^(hostname|user|port)'
201
ssh -G falticeni.radius-db | grep -E '^(hostname|user|port|connecttimeout)'
202
```
203

            
204
Verificare read-only cu conectare:
205

            
206
```bash
207
ssh porta-db hostname
208
ssh porta-sip 'service porta-sip status'
209
ssh voip-prov hostname
210
scp porta-db:/etc/hosts /tmp/test-scp
211
sftp porta-db <<< 'ls /'
212
```
213

            
214
## Mentenanta
215

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