SSH-Infrastructure / KEYS_AND_ACCESS.md
Newer Older
268 lines | 7.194kb
Bogdan Timofte authored 2 weeks ago
1
# SSH Keys and Access Guide
2

            
3
Centralized reference for SSH key management and access paths.
4

            
5
## Key Files Location
6

            
7
All SSH keys are stored in `~/.ssh/keys/`:
8

            
9
```
10
~/.ssh/keys/
11
  id_ed25519           → ~/.ssh/id_ed25519 (modern, preferred)
12
  id_ed25519_2026-05
13
  id_ed25519_2026-05.pub
14
  id_rsa               (RSA legacy, 2048-bit)
15
  id_rsa_old           (deprecated, from 2015)
16
  id_rsa_old.pub
17
  is-jumper_ed25519    (specific to is-jumper entry point)
18
  is-jumper_ed25519.pub
19
```
20

            
21
## Key Usage Matrix
22

            
23
| Key | File | Used By | Auth Method | Hosts |
24
|-----|------|---------|-------------|-------|
25
| **Modern ED25519** | `~/.ssh/id_ed25519` | most systems | pubkey | All modern hosts, J1, J2, local lab |
26
| **is-jumper ED25519** | `~/.ssh/keys/is-jumper_ed25519` | is-jumper (entry point) | pubkey + IdentitiesOnly | Entry point `192.168.2.100` |
27
| **Legacy RSA** | `~/.ssh/id_rsa` | legacy systems | pubkey | Old hosts still on RSA auth |
28
| **Deprecated RSA** | `~/.ssh/keys/id_rsa_old` | final fallback | pubkey | Hosts not yet migrated (being phased out) |
29

            
30
## Access Paths and Routing
31

            
32
### 1. Local Lab Setup (192.168.2.0/24)
33

            
34
**Direct access** — no jump needed:
35

            
36
```
37
is-jumper (192.168.2.100)
38
├─ User: root
39
├─ Port: 22
40
├─ Key: ~/.ssh/keys/is-jumper_ed25519
41
├─ IdentitiesOnly: yes
42
└─ Routing: SSH_ROUTE=local
43

            
44
Local dev machines (192.168.2.110-122)
45
├─ User: bogdan
46
├─ Port: 22
47
└─ Key: ~/.ssh/id_ed25519
48
```
49

            
50
Access to is-jumper:
51

            
52
```bash
53
# Direct connection (SSH will use is-jumper_ed25519 via IdentitiesOnly)
54
ssh is-jumper
55

            
56
# Verify key in use:
57
ssh -G is-jumper | grep identityfile
58
```
59

            
60
### 2. Production: Via is-jumper → J1/J2 → Final Hosts
61

            
62
**Access chain for internal company network (10.253.51.0/24)**:
63

            
64
```
65
Your machine (local)
66
  ↓ (ProxyJump is-jumper)
67
is-jumper (192.168.2.100) [VPN client + key guardian]
68
  ↓ (SSH forward)
69
J1 (10.253.51.50:25904) or J2 (10.253.51.52:25904) [jump hosts]
70
  ↓ (SSH forward)
71
Final host (voip, porta, radius, etc.)
72
```
73

            
74
#### Step 1: is-jumper (entry point)
75

            
76
- **User**: root
77
- **Host**: 192.168.2.100
78
- **Port**: 22
79
- **Key**: `~/.ssh/keys/is-jumper_ed25519`
80
- **IdentitiesOnly**: yes (forces use of specified key only)
81

            
82
```bash
83
ssh is-jumper
84
```
85

            
86
#### Step 2: J1/J2 (jump hosts)
87

            
88
**Reached through is-jumper via ProxyJump**:
89

            
90
- **User**: bogdan.timofte (jump host default)
91
- **Hostname**: 10.253.51.50 (J1) or 10.253.51.52 (J2)
92
- **Port**: 25904
93
- **Key**: `~/.ssh/id_ed25519` (offered by SSH client)
94
- **ProxyJump**: is-jumper (configured in ~/.ssh/config)
95

            
96
```bash
97
ssh j1        # Routes: local → is-jumper → J1
98
ssh j2        # Routes: local → is-jumper → J2
99

            
100
# Interactive jump host session:
101
ssh -J is-jumper bogdan.timofte@10.253.51.50 -p 25904
102
```
103

            
104
**Verify J1 config**:
105

            
106
```bash
107
ssh -G j1 | grep -E '^(hostname|port|user|proxyjump|identityfile)'
108
```
109

            
110
#### Step 3: Final Hosts
111

            
112
**From J1/J2 to actual hosts** (configured in J1's/J2's local SSH config):
113

            
114
- **User**: varies by host group (bogdan, bogdan.timofte, root, etc.)
115
- **Port**: 22 (standard) or 24 (jump hosts default) or custom
116
- **Key**: `~/.ssh/id_ed25519`
117
- **ProxyJump**: j1 or j2
118

            
119
```bash
120
# Example: PortaOne database server
121
ssh porta-db        # → is-jumper → J1 → 193.16.148.11
122

            
123
# Example: VoIP PBX
124
ssh voip-prov       # → is-jumper → J1 → 10.253.51.139
125

            
126
# Example: Radius database
127
ssh falticeni.radius-db  # → is-jumper → J1 → falticeni.radius-db:24
128
```
129

            
130
### 3. Emergency Public Routes (j1.next-gen.ro / j2.next-gen.ro)
131

            
132
If internal VPN is down, use public DNS names:
133

            
134
```bash
135
# Standard (internal VPN)
136
ssh j1              # 10.253.51.50:25904
137

            
138
# Emergency (public DNS)
139
ssh j1.next-gen.ro  # j1.next-gen.ro:25904
140
ssh j2.next-gen.ro  # j2.next-gen.ro:25904
141
```
142

            
143
Both routes go through is-jumper first (no direct connection).
144

            
145
## Key Migration Status
146

            
147
### Check which hosts have modern keys
148

            
149
```bash
150
# Test all local lab hosts
151
for h in is-baobab is-ebony is-tapia is-jumper is-mazeri is-toltec is-andrafiabe is-anjohibe is-nasturel is-mat; do
152
  timeout 2 ssh -o BatchMode=yes "$h" true 2>/dev/null && echo "$h: ✓" || echo "$h: ⚠"
153
done
154
```
155

            
156
### Migrate a host to modern ED25519 key
157

            
158
```bash
159
# Automatic migration (uses legacy key to install modern key)
160
tools/migrate-modern-key.sh is-baobab
161

            
162
# Or migrate all
163
tools/migrate-modern-key.sh
164
```
165

            
166
See [docs/KEY_MIGRATION.md](docs/KEY_MIGRATION.md) for manual procedures.
167

            
168
## SSH Config Generation
169

            
170
The `~/.ssh/config` is **auto-generated** from inventory — do not edit manually.
171

            
172
```bash
173
# Regenerate after inventory changes
174
python3 tools/generate-configs.py
175

            
176
# Deploy to ~/.ssh/config
177
cp generated/client.conf ~/.ssh/config
178
# or use the deploy script:
179
tools/deploy-local.sh
180
```
181

            
182
**Config files generated**:
183

            
184
| File | Target | Purpose |
185
|------|--------|---------|
186
| `generated/client.conf` | local client (~/.ssh/config) | local access config |
187
| `generated/is-jumper.conf` | is-jumper (via deploy) | is-jumper alias config |
188
| `generated/j1.conf` | J1 (server-side) | final host access on J1 |
189
| `generated/j2.conf` | J2 (server-side) | final host access on J2 |
190

            
191
## Troubleshooting
192

            
193
### "Permission denied (publickey)"
194

            
195
**Diagnosis**:
196

            
197
```bash
198
# Check which key is being offered
199
ssh -vvv porta-db 2>&1 | grep -E "Offering|Authentications"
200

            
201
# Check ProxyJump chain
202
ssh -vvv j1 2>&1 | grep -E "ProxyJump|Connecting"
203
```
204

            
205
**Solutions**:
206

            
207
1. **On is-jumper** — verify IdentitiesOnly and key:
208
   ```bash
209
   ssh -G is-jumper | grep identities
210
   ```
211
   Should show: `identitiesonly yes` and `identityfile ~/.ssh/keys/is-jumper_ed25519`
212

            
213
2. **On J1/J2** — verify modern key is installed:
214
   ```bash
215
   ssh is-jumper "ssh-keygen -l -f /home/bogdan.timofte/.ssh/authorized_keys"
216
   ```
217
   Should include ED25519 fingerprints.
218

            
219
3. **Regenerate and redeploy config**:
220
   ```bash
221
   python3 tools/generate-configs.py && cp generated/client.conf ~/.ssh/config
222
   ```
223

            
224
### "No route to host" (10.253.51.x)
225

            
226
**Cause**: Trying to access internal IPs directly without is-jumper.
227

            
228
**Solution**: Verify ProxyJump is configured:
229

            
230
```bash
231
ssh -G vo52 | grep proxyjump
232
# Should output: proxyjump j1
233
```
234

            
235
### SSH hangs or timeouts
236

            
237
**For jump hosts** (reduce to 5-10 seconds):
238

            
239
```bash
240
ssh -o ConnectTimeout=5 is-jumper
241
ssh -o ConnectTimeout=5 j1
242
```
243

            
244
**Check network**:
245

            
246
```bash
247
# is-jumper reachable?
248
ping 192.168.2.100
249

            
250
# If behind firewall, may need port 22 open to is-jumper
251
```
252

            
253
## Maintenance Checklist
254

            
255
- [ ] Keep both `id_ed25519` and `id_rsa_old` until all hosts migrated
256
- [ ] After adding new hosts: run `tools/migrate-modern-key.sh <host>`
257
- [ ] After inventory changes: regenerate with `python3 tools/generate-configs.py`
258
- [ ] Periodically check: `ssh -G <alias>` to verify config without connecting
259
- [ ] Never manually edit `~/.ssh/config` — it's auto-generated
260
- [ ] Keep keys in `~/.ssh/keys/` with mode `600`
261

            
262
## References
263

            
264
- [Ed25519 vs RSA Security](https://ianix.com/pub/ed25519-deployment.html)
265
- [OpenSSH Manual](https://man.openbsd.org/ssh)
266
- [Project inventory structure](inventory/hosts.yaml)
267
- [Key migration procedures](docs/KEY_MIGRATION.md)
268
- [Architecture details](ARCHITECTURE.md) (legacy Romanian docs: `.doc/ssh-jump-architecture.md`)