SSH keys 101: generating, storing and rotating them without losing your mind

Most developers generate an SSH key once, add it to a handful of servers, and never think about it again. That works fine for a solo project. It falls apart the moment there is a team, multiple environments, and servers that outlive the people who set them up.

This is a practical guide to the parts of SSH key management that actually cause problems in the real world: generation, storage, sharing, and — the part everyone skips — revocation.

Generate keys with a purpose, not a habit

The default advice to “just run ssh-keygen” hides an important decision: one key per purpose, not one key for everything.

ssh-keygen -t ed25519 -C "deploy-prod-api-2026"

Ed25519 keys are shorter, faster, and just as secure as a 4096-bit RSA key for virtually all modern use cases. Naming the key by purpose in the comment (the -C flag) means that six months from now, when you are auditing authorized_keys on a server, you can tell at a glance what each entry is for instead of guessing from a random key fingerprint.

A single key reused across every personal project, every client server, and every CI pipeline is convenient right up until one of those systems is compromised — at which point every other system that trusted the same key is compromised too.

Where private keys should actually live

The private half of an SSH key should never be:

  • Emailed or sent over chat, even “just this once.”
  • Stored unencrypted in a repository, including private ones.
  • Left in a default ~/.ssh folder with no passphrase on a shared or work laptop.

It should be either passphrase-protected on the machine that uses it, or stored in a dedicated vault alongside the rest of a project’s credentials — the same place its API keys, environment variables, and database passwords live. Treating an SSH key differently from an API key because it “feels” different is exactly the kind of inconsistency that leads to it ending up somewhere insecure.

Sharing access without sharing keys

The single most common SSH mistake on a team is sharing one private key among multiple people so everyone can deploy. This is a security and accountability failure at the same time: nobody can tell who actually connected, and revoking access for one person means rotating the key — and updating every server — for everyone.

The correct pattern is the opposite of sharing: each person generates their own key pair, and their public key is added to each server’s authorized_keys. Access is granted per person and revoked per person, without touching anyone else’s setup.

CI/CD keys deserve their own rules

Deploy keys used by CI pipelines are a special case. They should:

  • Be scoped to the minimum the pipeline actually needs — a deploy key that can only pull one repository, not a personal key with broad access.
  • Be stored as encrypted secrets in the CI provider, never committed to the repository they deploy.
  • Be rotated whenever a pipeline is decommissioned or a service migrates providers, not left active indefinitely “just in case.”

A deploy key with no clear owner and no expiry is exactly the kind of credential that shows up in a security audit six months late.

Rotation and revocation: the part everyone skips

Generating a key is easy. Actually removing old, unused keys is the part that gets neglected — and it is the part that matters most for security.

A simple habit that prevents most of the damage: whenever someone leaves a project, or a server is decommissioned, remove the relevant public key from authorized_keys immediately, not “when we get to it.” Access control that depends on remembering to clean up later is access control that fails silently.

Set a recurring calendar reminder — quarterly is reasonable for most teams — to audit authorized_keys on production servers and compare it against who currently has an active reason to be there. Anything unaccounted for gets removed.

Bottom line

SSH keys are credentials like any other, and they deserve the same discipline as API keys and passwords: one key per purpose, private keys stored securely rather than scattered across machines, individual keys per person instead of shared ones, and a habit of revoking access the moment it is no longer needed. The technology is simple. The discipline is what actually keeps a team’s infrastructure safe.