Skip to content

SSH Key Management

Philosophy: One SSH key per device, never shared.

This document covers the complete SSH key architecture for accessing servers.


Table of Contents


Why Device-Specific Keys

The Architecture

┌──────────────────────────────────────────────┐
│  CLIENT DEVICES                               │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐   │
│  │  iPad    │  │ MacBook  │  │    PC    │   │
│  │          │  │          │  │          │   │
│  │ Key A    │  │ Key B    │  │ Key C    │   │
│  │ (private)│  │ (private)│  │ (private)│   │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘   │
│       │             │             │          │
└───────┼─────────────┼─────────────┼──────────┘
        │             │             │
        └─────────────┼─────────────┘
                      │ SSH
┌──────────────────────────────────────────────┐
│  SERVERS                                      │
│  ┌────────────────────────────────────────┐  │
│  │ ~/.ssh/authorized_keys                 │  │
│  │                                        │  │
│  │ ssh-ed25519 AAAA...iPad    kavi@ipad  │  │
│  │ ssh-ed25519 AAAA...MacBook kavi@mac   │  │
│  │ ssh-ed25519 AAAA...PC      kavi@pc    │  │
│  └────────────────────────────────────────┘  │
└──────────────────────────────────────────────┘

Benefits of Device-Specific Keys

  1. Granular Access Control
  2. Know exactly which device accessed which server when
  3. Audit trail in server logs: kavi@macbook vs kavi@ipad

  4. Easy Revocation

  5. Device lost or stolen? Remove only that key
  6. Other devices continue to work
  7. No need to regenerate keys on all devices

  8. Security Isolation

  9. Compromise of one device doesn't compromise others
  10. Each device has independent authentication
  11. Follows principle of least privilege

  12. Better Than Shared Keys

  13. Shared key anti-pattern: One key on USB drive, copied to all devices
  14. Problem: If one device is compromised, all access is compromised
  15. Problem: No way to track which device was used
  16. Device-specific: Each device has unique keypair

Key Generation

General Principle

Generate keys on the device where they will be used. Never generate a key on one device and copy it to another.

iPad

ssh-keygen -t ed25519 -C "kavi@ipad" -f ~/.ssh/id_ed25519_ipad

Prompts:

Enter passphrase (empty for no passphrase): [STRONG PASSPHRASE]
Enter same passphrase again: [REPEAT]

Generated files: - ~/.ssh/id_ed25519_ipad (private key, NEVER share) - ~/.ssh/id_ed25519_ipad.pub (public key, safe to share)

MacBook

ssh-keygen -t ed25519 -C "kavi@macbook" -f ~/.ssh/id_ed25519_macbook

Generated files: - ~/.ssh/id_ed25519_macbook (private key) - ~/.ssh/id_ed25519_macbook.pub (public key)

PC

ssh-keygen -t ed25519 -C "kavi@pc" -f ~/.ssh/id_ed25519_pc

Generated files: - ~/.ssh/id_ed25519_pc (private key) - ~/.ssh/id_ed25519_pc.pub (public key)

Passphrase Best Practices

Strong passphrase recommendations: - Minimum 15 characters - Mix of uppercase, lowercase, numbers, symbols - Use a password manager to generate and store - Store in device keychain (macOS Keychain, Windows Credential Manager)

Why passphrase is important: - Private key file can be stolen from device - Passphrase encrypts the private key - Without passphrase, stolen file = stolen access

Storing passphrases: - macOS: Keychain Access (automatic with ssh-add --apple-use-keychain) - Windows: SSH Agent with Windows Credential Manager - Linux: ssh-agent + keychain manager


Adding Keys to Servers

Prerequisites

  1. You need initial access to the server (password, existing key, or server console)
  2. You have generated SSH keys on your device
  3. You have the public key content ready

View Your Public Key

# macOS/Linux
cat ~/.ssh/id_ed25519_macbook.pub

# Output example:
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFY4noi6kS88SH2OvEToerJZd4Ut/zQxfFE7yLFjcW1k kavi@macbook
# For Hetzner
ssh-copy-id -i ~/.ssh/id_ed25519_macbook.pub kavi@100.80.53.55

# For Kimsufi
ssh-copy-id -i ~/.ssh/id_ed25519_macbook.pub ubuntu@100.81.231.36

What this does: - Copies your public key to ~/.ssh/authorized_keys on the server - Sets correct permissions automatically - Validates key format

Method 2: Manual Addition

If ssh-copy-id isn't available:

# 1. Copy public key to clipboard
cat ~/.ssh/id_ed25519_macbook.pub
# (copy the output)

# 2. SSH to server (with password or existing key)
ssh kavi@100.80.53.55

# 3. Add key to authorized_keys
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFY4noi6kS88SH2OvEToerJZd4Ut/zQxfFE7yLFjcW1k kavi@macbook" >> ~/.ssh/authorized_keys

# 4. Set correct permissions
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh

# 5. Exit and test
exit
ssh kavi@100.80.53.55  # Should work without password

Adding Multiple Device Keys

Repeat the process for each device:

# From MacBook
ssh-copy-id -i ~/.ssh/id_ed25519_macbook.pub kavi@100.80.53.55

# From iPad
ssh-copy-id -i ~/.ssh/id_ed25519_ipad.pub kavi@100.80.53.55

# From PC
ssh-copy-id -i ~/.ssh/id_ed25519_pc.pub kavi@100.80.53.55

Result: All three devices can now SSH to the server.

authorized_keys will contain:

ssh-ed25519 AAAA...MacBook kavi@macbook
ssh-ed25519 AAAA...iPad kavi@ipad
ssh-ed25519 AAAA...PC kavi@pc


SSH Config Examples

Purpose of SSH Config

  • Simplify SSH commands (ssh hetzner instead of ssh kavi@100.80.53.55)
  • Store connection settings (port, user, key file)
  • Set keep-alive options

File Location

  • macOS/Linux: ~/.ssh/config
  • Windows: C:\Users\YourName\.ssh\config

Example Configuration

On MacBook (~/.ssh/config):

# Hetzner VPS (Germany)
Host hetzner
    HostName 100.80.53.55
    User kavi
    IdentityFile ~/.ssh/id_ed25519_macbook
    ServerAliveInterval 60
    ServerAliveCountMax 3

# Kimsufi (Canada)
Host kimsufi
    HostName 100.81.231.36
    User ubuntu
    IdentityFile ~/.ssh/id_ed25519_macbook
    ServerAliveInterval 60
    ServerAliveCountMax 3

# Storage Box (via SSH/SFTP)
Host storagebox
    HostName u522581.your-storagebox.de
    User u522581
    Port 23
    IdentityFile ~/.ssh/id_ed25519_macbook

# macOS Keychain integration
Host *
    AddKeysToAgent yes
    UseKeychain yes

On iPad (~/.ssh/config):

# Same as above, but change IdentityFile:
Host hetzner
    HostName 100.80.53.55
    User kavi
    IdentityFile ~/.ssh/id_ed25519_ipad  # Device-specific
    ServerAliveInterval 60
    ServerAliveCountMax 3

# ... repeat for other hosts

Configuration Options Explained

Option Purpose
Host hetzner Alias for the connection
HostName 100.80.53.55 Actual IP or domain
User kavi Username on remote server
IdentityFile ~/.ssh/id_ed25519_macbook Private key to use
ServerAliveInterval 60 Send keepalive every 60 seconds
ServerAliveCountMax 3 Disconnect after 3 failed keepalives
AddKeysToAgent yes Add key to SSH agent
UseKeychain yes (macOS) Store passphrase in Keychain

Usage After Configuration

# Before: Long command
ssh kavi@100.80.53.55

# After: Short alias
ssh hetzner

# Works with scp, rsync, etc.
scp file.txt hetzner:/path/to/destination
rsync -avz /local/dir hetzner:/remote/dir

Key Rotation

When to Rotate Keys

  • Annually: Proactive security practice
  • Device lost/stolen: Immediately
  • Device sold/given away: Before transfer
  • Suspicious activity: If you suspect compromise
  • Employee offboarding: When team member leaves

Rotation Process

Step 1: Generate new key on device

# Rename old key (backup)
mv ~/.ssh/id_ed25519_macbook ~/.ssh/id_ed25519_macbook.old
mv ~/.ssh/id_ed25519_macbook.pub ~/.ssh/id_ed25519_macbook.pub.old

# Generate new key
ssh-keygen -t ed25519 -C "kavi@macbook" -f ~/.ssh/id_ed25519_macbook

Step 2: Add new key to servers

ssh-copy-id -i ~/.ssh/id_ed25519_macbook.pub kavi@100.80.53.55
ssh-copy-id -i ~/.ssh/id_ed25519_macbook.pub ubuntu@100.81.231.36

Step 3: Remove old key from servers

# SSH to server
ssh hetzner

# Edit authorized_keys
nano ~/.ssh/authorized_keys

# Find and DELETE the old key line (look for old comment)
# Save and exit

# Repeat for all servers

Step 4: Test new key

# Exit and reconnect
exit
ssh hetzner  # Should work with new key

Step 5: Delete old key locally

# After verifying new key works
rm ~/.ssh/id_ed25519_macbook.old
rm ~/.ssh/id_ed25519_macbook.pub.old

Revoking a Lost Device Key

If iPad is lost:

# 1. SSH from another device (MacBook)
ssh hetzner

# 2. Edit authorized_keys
nano ~/.ssh/authorized_keys

# 3. DELETE the line containing "kavi@ipad"
# Save and exit

# 4. Repeat for all servers

Result: iPad can no longer access servers, but MacBook and PC still can.


Emergency Access

What if ALL SSH keys are lost?

Hetzner VPS (Cloud-based): 1. Log in to Hetzner Cloud Console: https://console.hetzner.cloud 2. Select your server 3. Click "Console" (VNC access) 4. Log in with password (if set) or reset password 5. Add new SSH key to ~/.ssh/authorized_keys

Kimsufi (Dedicated Server): 1. Log in to OVH Manager: https://www.ovh.com/manager/ 2. Select your Kimsufi server 3. Boot into rescue mode 4. Access via SSH (rescue mode credentials emailed) 5. Mount main filesystem 6. Add new SSH key to /mnt/home/ubuntu/.ssh/authorized_keys 7. Reboot to normal mode

Emergency SSH Key in Safe

Best practice: Keep ONE emergency SSH key pair: - Generate on a secure computer - Store private key on encrypted USB drive - Add public key to all servers - Put USB drive in physical safe - Only use in true emergency

Setup:

# Generate emergency key
ssh-keygen -t ed25519 -C "kavi@emergency" -f /path/to/usb/emergency_key

# Add to servers
ssh-copy-id -i /path/to/usb/emergency_key.pub kavi@100.80.53.55
ssh-copy-id -i /path/to/usb/emergency_key.pub ubuntu@100.81.231.36

# Store USB in safe


CRITICAL: Never Put SSH Keys in Secrets Managers

Why SSH Keys Must Stay Separate

❌ NEVER DO THIS:

1. Generate SSH key
2. Add to Infisical/Doppler
3. Fetch from secrets manager
4. Use to SSH

WHY THIS BREAKS:
- You need SSH to access the server
- Infisical runs ON the server
- Circular dependency: Need SSH to get SSH key
- If Infisical fails, you're locked out

The Correct Architecture

✅ CORRECT ARCHITECTURE:

SSH Keys: On client devices (iPad, MacBook, PC)
SSH to Server: Using device-specific keys
Access Infisical: Running on server
Fetch Application Secrets: API keys, database passwords, etc.

What Goes Where

Item Location Managed By
SSH Private Keys Client device only Device filesystem
SSH Public Keys Server authorized_keys Manual or ssh-copy-id
API Keys Infisical Secrets manager
Database Passwords Infisical Secrets manager
Service Tokens Infisical Secrets manager
Infisical ENCRYPTION_KEY Server ~/infisical/.env + encrypted backups Manual backup

The Lockout Risk

Scenario: You put SSH keys in Doppler/Infisical

Day 1: Everything works fine
Day 30: Infisical server crashes
Result:
- Can't SSH to server (need Infisical to get SSH key)
- Can't access Infisical (it's on the server)
- Can't fix Infisical (can't SSH to server)
- TOTAL LOCKOUT

With device-specific keys:

Day 30: Infisical server crashes
Result:
- SSH to server with device key ✅
- Restart Infisical ✅
- Everything works again ✅

SSH Keys Are Authentication TO Infrastructure

Think of it this way: - SSH keys: The keys to the building - Secrets manager: A safe inside the building - Application secrets: Money in the safe

You can't store the building keys inside the safe in the building. You keep building keys on your person (device).


File Permissions

Correct Permissions

# Private key: Read/write for owner only
chmod 600 ~/.ssh/id_ed25519_macbook

# Public key: Read for all, write for owner
chmod 644 ~/.ssh/id_ed25519_macbook.pub

# SSH directory: Owner access only
chmod 700 ~/.ssh

# authorized_keys on server: Read/write for owner only
chmod 600 ~/.ssh/authorized_keys

Why Permissions Matter

SSH refuses to use keys with incorrect permissions:

❌ Permission 0644 for 'id_ed25519_macbook' are too open.
   It is required that your private key files are NOT accessible by others.
   This private key will be ignored.

Security reason: If other users can read your private key, it's compromised.


Troubleshooting

"Permission denied (publickey)"

Possible causes: 1. Public key not added to server 2. Wrong private key being used 3. Wrong username 4. SSH config pointing to wrong key

Debug steps:

# Verbose SSH output
ssh -v kavi@100.80.53.55

# Look for:
# "Offering public key: /Users/kavi/.ssh/id_ed25519_macbook"
# "Authentications that can continue: publickey" (means key rejected)

Fix:

# Ensure key is added
ssh-copy-id -i ~/.ssh/id_ed25519_macbook.pub kavi@100.80.53.55

"WARNING: UNPROTECTED PRIVATE KEY FILE!"

Cause: Private key has wrong permissions (too permissive)

Fix:

chmod 600 ~/.ssh/id_ed25519_macbook

"Host key verification failed"

Cause: Server's fingerprint changed (reinstalled OS, different server, MITM attack)

Fix (if you know server was reinstalled):

ssh-keygen -R 100.80.53.55
ssh kavi@100.80.53.55  # Accept new fingerprint

SSH key not being used

Cause: SSH agent has too many keys (tries first 5, then gives up)

Fix:

# Clear SSH agent
ssh-add -D

# Add only needed key
ssh-add ~/.ssh/id_ed25519_macbook

# Or specify key explicitly
ssh -i ~/.ssh/id_ed25519_macbook kavi@100.80.53.55


Security Best Practices

  1. One key per device (not one key for all devices)
  2. Strong passphrases (15+ characters)
  3. Store in device keychain (macOS Keychain, Windows Credential Manager)
  4. Rotate annually (or when device changes hands)
  5. Revoke immediately (if device lost/stolen)
  6. Keep private keys private (never copy between devices)
  7. Use ed25519 algorithm (modern, secure, fast)
  8. Correct file permissions (600 for private, 644 for public)
  9. NEVER put in secrets managers (Infisical, Doppler, etc.)
  10. NEVER commit to git (even private repos)
  11. NEVER email keys (public keys OK, private keys NEVER)
  12. NEVER share keys between devices

Quick Reference

Generate Key

ssh-keygen -t ed25519 -C "kavi@device" -f ~/.ssh/id_ed25519_device

Add to Server

ssh-copy-id -i ~/.ssh/id_ed25519_device.pub user@server

Test Connection

ssh -v user@server

Remove Key from Server

ssh user@server
nano ~/.ssh/authorized_keys
# Delete the key line

View Public Key

cat ~/.ssh/id_ed25519_device.pub