Showing 2 changed files with 225 additions and 0 deletions
+126 -0
docs/KEY_MIGRATION.md
@@ -0,0 +1,126 @@
1
+# SSH Key Migration: Legacy to Modern
2
+
3
+## Overview
4
+
5
+This document describes the process for migrating hosts from legacy SSH keys (`id_rsa_old`) to modern keys (`id_ed25519`).
6
+
7
+## Rationale
8
+
9
+- **Legacy key** (`id_rsa_old` from 2015): RSA 2048-bit, older algorithm support
10
+- **Modern key** (`id_ed25519`): EdDSA 256-bit, better security, smaller key size, faster
11
+
12
+## Automatic Migration
13
+
14
+### Migrate all legacy hosts
15
+
16
+```bash
17
+tools/migrate-modern-key.sh
18
+```
19
+
20
+This will:
21
+1. Check all hosts in `inventory/hosts-local.yaml` legacy_infrastructure group
22
+2. Test if modern key already works
23
+3. Use legacy key to install modern key if needed
24
+4. Verify modern key works after installation
25
+
26
+### Migrate specific host
27
+
28
+```bash
29
+tools/migrate-modern-key.sh is-baobab
30
+```
31
+
32
+## Manual Migration (if script fails)
33
+
34
+For a specific host, e.g., `is-nasturel`:
35
+
36
+### 1. Interactive password auth
37
+
38
+If password is available:
39
+
40
+```bash
41
+ssh -o PubkeyAuthentication=no sshd@192.168.2.144 \
42
+  "mkdir -p ~/.ssh && \
43
+   echo '$(cat ~/.ssh/id_ed25519.pub)' >> ~/.ssh/authorized_keys && \
44
+   chmod 600 ~/.ssh/authorized_keys"
45
+```
46
+
47
+### 2. Through jump host (is-jumper)
48
+
49
+If accessible through is-jumper:
50
+
51
+```bash
52
+ssh is-jumper \
53
+  "ssh -o StrictHostKeyChecking=accept-new sshd@192.168.2.144 \
54
+    'mkdir -p ~/.ssh && echo \$(cat ~/.ssh/id_ed25519.pub) >> ~/.ssh/authorized_keys'"
55
+```
56
+
57
+### 3. Physical/console access
58
+
59
+If all else fails, use console/IPMI access to manually:
60
+- Edit `/home/sshd/.ssh/authorized_keys`
61
+- Add modern key: `ssh-ed25519 AAAAC3NzaC1lZDI1NTE5...`
62
+
63
+## Adding New Hosts
64
+
65
+When adding new legacy hosts to the inventory:
66
+
67
+1. **In `inventory/hosts-local.yaml`**: add host to `legacy_infrastructure` group
68
+2. **Run deployment**: `tools/deploy-local.sh`
69
+3. **Run migration**: `tools/migrate-modern-key.sh <new-host>`
70
+4. **Commit**: `git add . && git commit -m "Add/migrate <host>"`
71
+
72
+## Status Tracking
73
+
74
+Check which hosts have been migrated:
75
+
76
+```bash
77
+# Modern key working
78
+for h in $(grep -oE "is-[a-z0-9-]+" inventory/hosts-local.yaml | sort -u); do
79
+  timeout 1 ssh -o BatchMode=yes "$h" true 2>/dev/null && echo "$h: ✓" || echo "$h: ⚠"
80
+done
81
+```
82
+
83
+## Key Files
84
+
85
+- **Modern (preferred)**: `~/.ssh/id_ed25519`
86
+- **Legacy (deprecated)**: `~/.ssh/keys/id_rsa_old`
87
+
88
+Both should be kept until all hosts are migrated.
89
+
90
+## Removing Legacy Key
91
+
92
+Once all hosts migrated and verified:
93
+
94
+```bash
95
+# Backup first
96
+cp ~/.ssh/keys/id_rsa_old ~/.ssh/keys/id_rsa_old.backup
97
+
98
+# Remove from SSH config (if any explicit config)
99
+grep -r "id_rsa_old" . && echo "Still in use" || echo "Safe to remove"
100
+
101
+# Safe to delete after backup
102
+rm ~/.ssh/keys/id_rsa_old
103
+```
104
+
105
+## Troubleshooting
106
+
107
+### "Permission denied (publickey)" with modern key
108
+
109
+→ Host still using legacy auth only. Use `tools/migrate-modern-key.sh <host>`
110
+
111
+### Legacy key also fails to connect
112
+
113
+→ Host might be offline or firewall blocked. Check connectivity first:
114
+
115
+```bash
116
+ping 192.168.2.91  # Replace with host IP
117
+```
118
+
119
+### SSH hangs or times out
120
+
121
+→ Reduce timeout, check firewall rules. Use `-o ConnectTimeout=2` flag.
122
+
123
+## References
124
+
125
+- [Ed25519 SSH keys - OpenSSH](https://man.openbsd.org/ssh-keygen)
126
+- [Why Ed25519 is superior to RSA](https://ianix.com/pub/ed25519-deployment.html)
+99 -0
tools/migrate-modern-key.sh
@@ -0,0 +1,99 @@
1
+#!/usr/bin/env bash
2
+# Migrate legacy SSH key (id_rsa_old) to modern key (id_ed25519) on hosts
3
+# Usage: ./tools/migrate-modern-key.sh [host-alias]
4
+# If no host specified, migrates all legacy hosts
5
+
6
+set -euo pipefail
7
+
8
+project_root=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
9
+modern_key_file="$HOME/.ssh/id_ed25519.pub"
10
+legacy_key_file="$HOME/.ssh/keys/id_rsa_old"
11
+
12
+if [[ ! -f "$modern_key_file" ]]; then
13
+    printf "Error: Modern key not found at %s\n" "$modern_key_file" >&2
14
+    exit 1
15
+fi
16
+
17
+if [[ ! -f "$legacy_key_file" ]]; then
18
+    printf "Error: Legacy key not found at %s\n" "$legacy_key_file" >&2
19
+    exit 1
20
+fi
21
+
22
+modern_key=$(cat "$modern_key_file")
23
+
24
+migrate_host() {
25
+    local host=$1
26
+    local ip
27
+    local user
28
+
29
+    # Get host config
30
+    ip=$(ssh -G "$host" 2>/dev/null | grep "^hostname " | cut -d' ' -f2) || {
31
+        printf "Error: Cannot resolve host %s\n" "$host" >&2
32
+        return 1
33
+    }
34
+
35
+    user=$(ssh -G "$host" 2>/dev/null | grep "^user " | cut -d' ' -f2) || user="root"
36
+
37
+    printf "Migrating %s (%s@%s)...\n" "$host" "$user" "$ip"
38
+
39
+    # Try with modern key first (might already be migrated)
40
+    if timeout 2 ssh -o BatchMode=yes -o ConnectTimeout=1 "$host" "true" 2>/dev/null; then
41
+        printf "  ✓ Already using modern key\n"
42
+        return 0
43
+    fi
44
+
45
+    # Try legacy key to install modern key
46
+    if timeout 5 ssh -i "$legacy_key_file" -o StrictHostKeyChecking=accept-new \
47
+        -o ConnectTimeout=2 "${user}@${ip}" \
48
+        "mkdir -p ~/.ssh && \
49
+         grep -q '$(printf '%s' "$modern_key" | sed 's/[&/\]/\\&/g')' ~/.ssh/authorized_keys 2>/dev/null || \
50
+         echo '$modern_key' >> ~/.ssh/authorized_keys && \
51
+         chmod 600 ~/.ssh/authorized_keys && \
52
+         echo 'OK'" 2>/dev/null; then
53
+        printf "  ✓ Modern key installed\n"
54
+
55
+        # Verify
56
+        sleep 1
57
+        if timeout 2 ssh -o BatchMode=yes -o ConnectTimeout=1 "$host" "true" 2>/dev/null; then
58
+            printf "  ✓ Verified\n"
59
+            return 0
60
+        else
61
+            printf "  ⚠ Installation ok, verification pending\n"
62
+            return 1
63
+        fi
64
+    else
65
+        printf "  ✗ Legacy key access failed\n"
66
+        return 1
67
+    fi
68
+}
69
+
70
+if [[ $# -gt 0 ]]; then
71
+    # Migrate specific host
72
+    migrate_host "$1"
73
+else
74
+    # Migrate all legacy hosts
75
+    printf "=== Migrating all legacy hosts to modern key ===\n\n"
76
+
77
+    failed=()
78
+    success=()
79
+
80
+    while IFS= read -r host; do
81
+        if migrate_host "$host"; then
82
+            success+=("$host")
83
+        else
84
+            failed+=("$host")
85
+        fi
86
+        printf "\n"
87
+    done < <(grep -E "^Host is-" "$project_root/inventory/hosts-local.yaml" \
88
+        | grep -oE "is-[a-z0-9-]+" | sort -u)
89
+
90
+    printf "\n=== Migration Summary ===\n"
91
+    printf "Success: %d\n" "${#success[@]}"
92
+    printf "Failed: %d\n" "${#failed[@]}"
93
+
94
+    if [[ ${#failed[@]} -gt 0 ]]; then
95
+        printf "\nFailed hosts:\n"
96
+        printf "  %s\n" "${failed[@]}"
97
+        exit 1
98
+    fi
99
+fi