Critical update: explain that: - Physical card key (RSA 4096) is ONLY on is-jumper - J1/J2 authentication uses the physical card via GPG agent, not file-based keys - Users cannot access J1/J2 directly; all access must proxy through is-jumper - SSH agent forwarding carries the physical key through the proxy chain Update key usage matrix to show physical card as primary auth for company network Expand troubleshooting to cover: - Card key not exposed or SSH agent not running - Agent forwarding not configured - Physical card re-mounting issues This explains why "Permission denied" to J1 was happening — the physical card authentication mechanism wasn't documented. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@@ -2,9 +2,9 @@ |
||
| 2 | 2 |
|
| 3 | 3 |
Centralized reference for SSH key management and access paths. |
| 4 | 4 |
|
| 5 |
-## Key Files Location |
|
| 5 |
+## Key Storage |
|
| 6 | 6 |
|
| 7 |
-All SSH keys are stored in `~/.ssh/keys/`: |
|
| 7 |
+### Local Keys (on your machine) |
|
| 8 | 8 |
|
| 9 | 9 |
``` |
| 10 | 10 |
~/.ssh/keys/ |
@@ -18,14 +18,29 @@ All SSH keys are stored in `~/.ssh/keys/`: |
||
| 18 | 18 |
is-jumper_ed25519.pub |
| 19 | 19 |
``` |
| 20 | 20 |
|
| 21 |
+### Physical Hardware Key (on is-jumper) |
|
| 22 |
+ |
|
| 23 |
+**⚠️ IMPORTANT**: The primary authentication for the **company network (J1/J2)** is a **physical hardware security key (card/smartcard)** mounted **only on is-jumper** (192.168.2.100). |
|
| 24 |
+ |
|
| 25 |
+- **Location**: is-jumper (192.168.2.100) only |
|
| 26 |
+- **Type**: Hardware security module / smartcard (RSA 4096-bit) |
|
| 27 |
+- **Exposed via**: GPG agent at `/run/user/0/gnupg/S.gpg-agent.ssh` (on is-jumper) |
|
| 28 |
+- **Access method**: SSH agent forwarding through is-jumper |
|
| 29 |
+- **Users served**: Multiple users from the 192.168.2.0/24 network |
|
| 30 |
+ |
|
| 31 |
+**You cannot access J1/J2 directly from your local machine.** The connection must go through is-jumper, which holds the only valid physical key for the company network. |
|
| 32 |
+ |
|
| 21 | 33 |
## Key Usage Matrix |
| 22 | 34 |
|
| 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) | |
|
| 35 |
+| Key | Location | Used By | Purpose | Auth Method | |
|
| 36 |
+| --- | --- | --- | --- | --- | |
|
| 37 |
+| **Physical card (RSA 4096)** | Hardware on is-jumper only | J1, J2, company network | Primary auth for nextgen network | Hardware smartcard via GPG agent | |
|
| 38 |
+| **is-jumper ED25519** | `~/.ssh/keys/is-jumper_ed25519` | Your machine → is-jumper | Access the entry point | pubkey + IdentitiesOnly | |
|
| 39 |
+| **Modern ED25519** | `~/.ssh/id_ed25519` | Local lab, final hosts | Secondary/fallback auth | pubkey | |
|
| 40 |
+| **Legacy RSA** | `~/.ssh/id_rsa` | Legacy systems | Transitional | pubkey | |
|
| 41 |
+| **Deprecated RSA** | `~/.ssh/keys/id_rsa_old` | Very old hosts | Final fallback | pubkey | |
|
| 42 |
+ |
|
| 43 |
+**Key insight**: You authenticate TO is-jumper with your local ED25519 key, but once on is-jumper, the system uses the **physical hardware key** to authenticate to the company network (J1/J2). |
|
| 29 | 44 |
|
| 30 | 45 |
## Access Paths and Routing |
| 31 | 46 |
|
@@ -63,16 +78,20 @@ ssh -G is-jumper | grep identityfile |
||
| 63 | 78 |
|
| 64 | 79 |
``` |
| 65 | 80 |
Your machine (local) |
| 66 |
- ↓ (ProxyJump is-jumper) |
|
| 67 |
-is-jumper (192.168.2.100) [VPN client + key guardian] |
|
| 68 |
- ↓ (SSH forward) |
|
| 81 |
+ ↓ (ED25519 pubkey) |
|
| 82 |
+is-jumper (192.168.2.100) [VPN client + physical card key guardian] |
|
| 83 |
+ ↓ (SSH agent forwarding + physical card RSA 4096) |
|
| 69 | 84 |
J1 (10.253.51.50:25904) or J2 (10.253.51.52:25904) [jump hosts] |
| 70 | 85 |
↓ (SSH forward) |
| 71 | 86 |
Final host (voip, porta, radius, etc.) |
| 72 | 87 |
``` |
| 73 | 88 |
|
| 89 |
+**Critical**: You cannot connect to J1/J2 directly from your local machine because the physical hardware key is **only on is-jumper**. All company network access must go through is-jumper first. |
|
| 90 |
+ |
|
| 74 | 91 |
#### Step 1: is-jumper (entry point) |
| 75 | 92 |
|
| 93 |
+Authenticate to is-jumper with your local ED25519 key: |
|
| 94 |
+ |
|
| 76 | 95 |
- **User**: root |
| 77 | 96 |
- **Host**: 192.168.2.100 |
| 78 | 97 |
- **Port**: 22 |
@@ -83,28 +102,28 @@ Final host (voip, porta, radius, etc.) |
||
| 83 | 102 |
ssh is-jumper |
| 84 | 103 |
``` |
| 85 | 104 |
|
| 86 |
-#### Step 2: J1/J2 (jump hosts) |
|
| 105 |
+Once logged in, is-jumper has access to the physical card key via GPG agent at `/run/user/0/gnupg/S.gpg-agent.ssh`. |
|
| 87 | 106 |
|
| 88 |
-**Reached through is-jumper via ProxyJump**: |
|
| 107 |
+#### Step 2: J1/J2 (jump hosts) — via is-jumper's physical key |
|
| 89 | 108 |
|
| 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) |
|
| 109 |
+**SSH agent forwarding** connects your SSH client to is-jumper's physical card: |
|
| 95 | 110 |
|
| 96 |
-```bash |
|
| 97 |
-ssh j1 # Routes: local → is-jumper → J1 |
|
| 98 |
-ssh j2 # Routes: local → is-jumper → J2 |
|
| 111 |
+- **Routing**: ProxyJump is-jumper |
|
| 112 |
+- **Authentication on J1/J2**: Physical card (RSA 4096) via `SSH_AUTH_SOCK=/run/user/0/gnupg/S.gpg-agent.ssh` |
|
| 113 |
+- **User on J1/J2**: `bogdan.timofte` (company network default) |
|
| 114 |
+- **Port**: 25904 (VPN jump port) |
|
| 99 | 115 |
|
| 100 |
-# Interactive jump host session: |
|
| 101 |
-ssh -J is-jumper bogdan.timofte@10.253.51.50 -p 25904 |
|
| 116 |
+```bash |
|
| 117 |
+ssh j1 # Routes: local → is-jumper → J1 (using is-jumper's physical key) |
|
| 118 |
+ssh j2 # Routes: local → is-jumper → J2 (using is-jumper's physical key) |
|
| 102 | 119 |
``` |
| 103 | 120 |
|
| 121 |
+**The SSH config handles this automatically** — you don't need to manually set up agent forwarding. The wrapper or ProxyJump chain uses is-jumper's physical key to authenticate. |
|
| 122 |
+ |
|
| 104 | 123 |
**Verify J1 config**: |
| 105 | 124 |
|
| 106 | 125 |
```bash |
| 107 |
-ssh -G j1 | grep -E '^(hostname|port|user|proxyjump|identityfile)' |
|
| 126 |
+ssh -G j1 | grep -E '^(hostname|port|user|proxyjump)' |
|
| 108 | 127 |
``` |
| 109 | 128 |
|
| 110 | 129 |
#### Step 3: Final Hosts |
@@ -190,48 +209,88 @@ tools/deploy-local.sh |
||
| 190 | 209 |
|
| 191 | 210 |
## Troubleshooting |
| 192 | 211 |
|
| 193 |
-### "Permission denied (publickey)" |
|
| 212 |
+### "Permission denied (publickey)" on J1/J2 |
|
| 213 |
+ |
|
| 214 |
+**⚠️ First check**: Do you have **access to is-jumper**? |
|
| 215 |
+ |
|
| 216 |
+```bash |
|
| 217 |
+ssh is-jumper "echo access ok" |
|
| 218 |
+``` |
|
| 219 |
+ |
|
| 220 |
+If this fails, the issue is your local ED25519 key or is-jumper authentication. Fix that first. |
|
| 221 |
+ |
|
| 222 |
+**If is-jumper works but J1 fails**: |
|
| 223 |
+ |
|
| 224 |
+The issue is likely the **physical card key is not properly exposed** or **SSH agent forwarding isn't working**. |
|
| 194 | 225 |
|
| 195 | 226 |
**Diagnosis**: |
| 196 | 227 |
|
| 197 | 228 |
```bash |
| 198 |
-# Check which key is being offered |
|
| 199 |
-ssh -vvv porta-db 2>&1 | grep -E "Offering|Authentications" |
|
| 229 |
+# 1. Check if you can reach is-jumper |
|
| 230 |
+ssh is-jumper |
|
| 231 |
+ |
|
| 232 |
+# 2. From is-jumper, verify the physical card is available |
|
| 233 |
+ssh is-jumper "ls -la /run/user/0/gnupg/S.gpg-agent.ssh" |
|
| 234 |
+# Should exist and be readable |
|
| 200 | 235 |
|
| 201 |
-# Check ProxyJump chain |
|
| 202 |
-ssh -vvv j1 2>&1 | grep -E "ProxyJump|Connecting" |
|
| 236 |
+# 3. Check J1 connectivity with verbose output |
|
| 237 |
+ssh -vvv j1 2>&1 | grep -E "ProxyJump|Offering|Authentications|Trying" |
|
| 203 | 238 |
``` |
| 204 | 239 |
|
| 205 | 240 |
**Solutions**: |
| 206 | 241 |
|
| 207 |
-1. **On is-jumper** — verify IdentitiesOnly and key: |
|
| 242 |
+1. **is-jumper's SSH agent not running**: |
|
| 208 | 243 |
```bash |
| 209 |
- ssh -G is-jumper | grep identities |
|
| 244 |
+ ssh is-jumper "ps aux | grep gpg-agent" |
|
| 245 |
+ # If not running, restart it or contact the system administrator |
|
| 210 | 246 |
``` |
| 211 |
- Should show: `identitiesonly yes` and `identityfile ~/.ssh/keys/is-jumper_ed25519` |
|
| 212 | 247 |
|
| 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. |
|
| 248 |
+2. **SSH config not set up for agent forwarding**: |
|
| 249 |
+ - Verify ProxyJump is configured: `ssh -G j1 | grep proxyjump` |
|
| 250 |
+ - Verify `ForwardAgent yes` is set (check generated config) |
|
| 251 |
+ |
|
| 252 |
+3. **Physical card key not accessible**: |
|
| 253 |
+ - This is a system issue on is-jumper — contact the key administrator |
|
| 254 |
+ - The card may need to be re-mounted or re-authenticated |
|
| 218 | 255 |
|
| 219 |
-3. **Regenerate and redeploy config**: |
|
| 256 |
+4. **SSH on your machine not supporting agent forwarding**: |
|
| 220 | 257 |
```bash |
| 221 |
- python3 tools/generate-configs.py && cp generated/client.conf ~/.ssh/config |
|
| 258 |
+ # Ensure SSH_AUTH_SOCK is set when you SSH to is-jumper |
|
| 259 |
+ ssh -A is-jumper |
|
| 222 | 260 |
``` |
| 223 | 261 |
|
| 262 |
+### "Permission denied (publickey)" on is-jumper |
|
| 263 |
+ |
|
| 264 |
+**The issue**: Your local ED25519 key isn't authorized on is-jumper. |
|
| 265 |
+ |
|
| 266 |
+**Verify your key is present**: |
|
| 267 |
+ |
|
| 268 |
+```bash |
|
| 269 |
+ls -la ~/.ssh/keys/is-jumper_ed25519 |
|
| 270 |
+cat ~/.ssh/keys/is-jumper_ed25519.pub |
|
| 271 |
+``` |
|
| 272 |
+ |
|
| 273 |
+**Check that is-jumper has your key**: |
|
| 274 |
+ |
|
| 275 |
+```bash |
|
| 276 |
+ssh is-jumper "cat ~/.ssh/authorized_keys | grep -i ed25519" |
|
| 277 |
+``` |
|
| 278 |
+ |
|
| 279 |
+If your key isn't there, it needs to be added by the is-jumper administrator. |
|
| 280 |
+ |
|
| 224 | 281 |
### "No route to host" (10.253.51.x) |
| 225 | 282 |
|
| 226 |
-**Cause**: Trying to access internal IPs directly without is-jumper. |
|
| 283 |
+**Cause**: Trying to reach J1/J2 directly without going through is-jumper. |
|
| 227 | 284 |
|
| 228 |
-**Solution**: Verify ProxyJump is configured: |
|
| 285 |
+**Check ProxyJump**: |
|
| 229 | 286 |
|
| 230 | 287 |
```bash |
| 231 |
-ssh -G vo52 | grep proxyjump |
|
| 232 |
-# Should output: proxyjump j1 |
|
| 288 |
+ssh -G j1 | grep proxyjump |
|
| 289 |
+# Must show: proxyjump is-jumper |
|
| 233 | 290 |
``` |
| 234 | 291 |
|
| 292 |
+If not, regenerate config: `python3 tools/generate-configs.py && cp generated/client.conf ~/.ssh/config` |
|
| 293 |
+ |
|
| 235 | 294 |
### SSH hangs or timeouts |
| 236 | 295 |
|
| 237 | 296 |
**For jump hosts** (reduce to 5-10 seconds): |