Skip to content

Instantly share code, notes, and snippets.

@ChristopherA
Last active October 28, 2024 22:52
Show Gist options
  • Save ChristopherA/3d6a2f39c4b623a1a287b3fb7e0aa05b to your computer and use it in GitHub Desktop.
Save ChristopherA/3d6a2f39c4b623a1a287b3fb7e0aa05b to your computer and use it in GitHub Desktop.
SSH Keys - Best Practices

SSH Keys Best Practices

(VERY rought draft, still a work-in-progress)

SSH Key Seperation

Authentication and signing keys serve different purposes, especially on platforms like GitHub where code integrity and access control are crucial. Here's a comparison based on their functions and best practices:

Authentication Keys:

  1. Purpose:

    • Authentication keys are used to authenticate users to a server, verifying the user's identity and granting them access to the repository based on the permissions associated with the key.
    • These keys are crucial for securely accessing repositories on GitHub, especially when collaborating on private repositories.
  2. Usage on GitHub:

    • Authentication keys can be added to your GitHub account to allow access to repositories.
    • When you add a new SSH authentication key to your GitHub account, you can reconfigure any local repositories to use SSH for secure access.
  3. Security Best Practices:

    • It's advisable to protect SSH keys with passphrases to add an extra layer of security.
    • Using hardware security keys is also a good practice as they provide a higher level of security. The private SSH key remains on the hardware and is not directly accessible from software, making it very difficult to compromise remotely.

Signing Keys:

  1. Purpose:

    • Signing keys are used to verify the integrity and origin of data, such as ensuring that commits have not been tampered with and indeed come from the indicated contributor.
    • They can be used to sign Git commits on GitHub, providing a way to verify that the commits are actually from the authenticated user and have not been altered.
  2. Usage on GitHub:

    • To sign commits using SSH on GitHub, you need to:
      • Check for existing SSH keys.
      • Generate a new SSH key if necessary.
      • Add the SSH signing key to your GitHub account.
      • Configure Git to know about your signing key.
      • Sign your commits and tags【64†source】.
    • If you already use an SSH key for authentication with GitHub, you can upload that same key again for use as a signing key. GitHub allows you to add multiple signing keys to your account【64†source】.
  3. Security Best Practices:

    • It's advisable to also protect signing keys with passphrases and consider using hardware security keys for enhanced security.

While authentication keys are about verifying a user's identity and granting them access to resources, signing keys are about verifying the integrity and origin of data. On GitHub, it's possible to use the same SSH key for both authentication and signing, but you need to upload it twice for these separate purposes, and is not a best practice. Utilizing two different keys in accordance with best practices enhances the security and integrity of your interactions on GitHub.

Naming

When managing SSH keys for different purposes such as authentication and signing, employing a clear and consistent naming convention is crucial to avoid confusion and maintain organization. Here are some suggestions for naming conventions to keep authentication and signing SSH keys separate:

  1. Prefixing/Suffixing by Purpose:

    • Prefix or suffix the key filenames with their purpose. For example:
      • auth_id_rsa or id_rsa_auth for authentication keys.
      • sign_id_rsa or id_rsa_sign for signing keys.
  2. Including the Service Name:

    • If the keys are used for a specific service like GitHub, include the service name in the filename:
      • github_auth_id_rsa or id_rsa_github_auth for GitHub authentication keys.
      • github_sign_id_rsa or id_rsa_github_sign for GitHub signing keys.
  3. Including Username or Identifier:

    • If multiple users are using the same system, include a username or identifier:
      • alice_auth_id_rsa or id_rsa_alice_auth for authentication keys.
      • alice_sign_id_rsa or id_rsa_alice_sign for signing keys.
  4. Including Key Algorithm:

    • If you are using different algorithms for keys (e.g., RSA, ECDSA, or EdDSA), you can include the algorithm name:
      • auth_id_ed25519 or id_ed25519_auth for authentication keys.
      • sign_id_ed25519 or id_ed25519_sign for signing keys.
  5. Including Date or Version:

    • Including a date or version number can help keep track of keys and identify old or deprecated keys:
      • auth_id_ed25519_20231025 or id_ed25519_auth_v1 for authentication keys.
      • sign_id_ed25519_20231025 or id_ed25519_sign_v1 for signing keys.
  6. Directory Structuring:

    • Keep authentication and signing keys in separate directories:
      • /path/to/ssh/keys/authentication/id_ed25519 for authentication keys.
      • /path/to/ssh/keys/signing/id_ed25519 for signing keys.
  7. Including Machine Name:

    • Including the machine name of computer the key is used on, to discourage key reuse across computers.
      • auth_id__ed25519_mymachine or id_auth__ed25519_mymachine.local for authentication keys.
      • sign_id__ed25519_mymachine or id_sign__ed25519_mymachine.local for signing keys.
  8. Combination:

    • Combine multiple elements from the above suggestions to create a detailed naming convention that suits your needs. For example:
      • github_alice_auth_id_ed25519_v1 for a specific version of an authentication key for user Alice on GitHub.
      • sign_id_ed25519_localusername_mymachine.local_mygithubusername@github

These conventions can be adapted or combined based on personal or organizational preferences to achieve a clear, organized system for managing SSH keys for different purposes. Remember to also maintain a secure backup and possibly a document mapping keys to their purposes, especially in a team or organizational setting, to ensure that the naming convention is understood and followed consistently.

SSH Namespaces

Creating and managing SSH keys for different purposes, ranging from regular SSH connections to commit signing, requires a clear understanding of namespaces and their role in maintaining security. While the official SSH documentation does not provide exhaustive guidelines specifically for namespaces, based on the best practices from various sources, here's how you can approach this:

  1. Purpose of Namespaces: SSH key namespaces are essentially identifiers that distinguish the intended use of a particular key. They prevent cross-protocol attacks and ensure that a key used in one context is not misappropriated in another.

  2. Namespace Examples:

    • file: Used for signing generic files.
    • email: Used for signing emails.
    • Custom namespaces: Can be defined for specific applications or protocols.

Some Best Practices for SSH Key Namespaces

  1. Separation of Keys: Maintain separate SSH keys for regular access and signing. This separation ensures that keys used for sensitive operations like signing are not exposed in less secure environments.

  2. Unique Namespaces for Signing Keys: When creating SSH keys for signing, assign them a unique namespace that reflects their purpose. For example, a key for signing documents might have a namespace like doc-signing@yourdomain.com.

  3. Global Uniqueness: Ensure that the namespaces you define are globally unique. A recommended approach is to structure them like an email address under a domain that you control.

  4. Key Generation: When generating SSH keys, use appropriate tools and specify the purpose in the comment field. For example, ssh-keygen -t rsa -C "doc-signing@yourdomain.com".

  5. Key Storage and Access: Store keys used for different purposes in separate directories or with clear naming conventions to avoid confusion.

  6. Key Usage: Use the keys strictly for their intended purpose. For example, do not use a key designated for regular SSH access for signing operations.

  7. Documentation: Document the purpose and use-case of each key, especially those with unique namespaces. This documentation is vital for audits and security reviews.

  8. Regular Audits and Rotation: Regularly audit your SSH keys and rotate them, particularly those used for critical operations like signing.

Implementing Namespaces in SSH Key Management

To implement these best practices, you'll need to integrate namespace considerations into your SSH key management strategy. This might include:

  • Updating your key generation scripts to include namespace information.
  • Educating team members about the importance of using the right keys for the right purposes.
  • Implementing monitoring and auditing tools to track the usage of keys and ensure compliance with your namespace strategy.

More General

The recommendation by cryptographers and security professionals is to separate the usage of keys. Authentication keys (the default usage SSH keys) should be kept segregated from Signing keys (the newer SSH functionality), and from other uses (such as Authorization or Capability keys, which not really used by SSH, but plausible).

More specifically, this is the recommendation by NIST in https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-57pt1r5.pdf section 5.5:

5.2 Key Usage

In general, a single key shall be used for only one purpose (e.g., encryption, integrity authentication, key wrapping, random bit generation, or digital signatures). There are several reasons for this:

  1. The use of the same key for two different cryptographic processes may weaken the security provided by one or both of the processes.
  2. Limiting the use of a key limits the damage that could be done if the key is compromised.
  3. Some uses of keys interfere with each other. For example, consider a key pair used for both key transport and digital signatures. In this case, the private key is used as both a private key-transport key to decrypt the encrypted keys and as a private signature key to generate digital signatures. It may be necessary to retain the private key used for transport key beyond the cryptoperiod of the corresponding public key in order to decrypt the encrypted keys needed to access encrypted data. The private key used for signature generation shall be destroyed at the expiration of its cryptoperiod to prevent its compromise (see Section 5.3.6). In this example, the longevity requirements for the private key-transport key and the private digital-signature key contradict each other.

In the newer W3C international standards such as DID and Verified Credential requires explicit different "proof purposes" and "keyUsage" requirements.

See: https://www.w3.org/TR/vc-data-integrity/#proof-purposes

The following is a list of commonly used proof purpose values.

  • authentication
    • Indicates that a given proof is only to be used for the purposes of an authentication protocol.
  • assertionMethod
    • Indicates that a proof can only be used for making assertions, for example signing a Verifiable Credential.
  • keyAgreement
    • Indicates that a proof is used for for key agreement protocols, such as Elliptic Curve Diffie Hellman key agreement used by popular encryption libraries.
  • capabilityDelegation
    • Indicates that the proof can only be used for delegating capabilities. See the Authorization Capabilities [ZCAP] specification for more detail.
  • capabilityInvocation
    • Indicates that the proof can only be used for invoking capabilities. See the Authorization Capabilities [ZCAP] specification for more detail.

You can also see these practices also exemplified for separation of SSH and PGP keys into FIDO2 devices.

See: https://gist.github.com/ageis/14adc308087859e199912b4c79c4aaa4?permalink_comment_id=2926757

In this guide, you will generate a master key with the Certify and Sign capabilities and two subkeys with each of the Encrypt and Authenticate capabilities respectively and move them to one YubiKey.

A basic grasp of the concept of capabilities of private keys is helpful, so here's a table for elucidation:

  • Certify
    • With this you may sign other keys, "certifying" them, indicating you verified their identity and trust that person. Ordinarily set on the primary/master key, this is required to add or revoke UIDs, alter key details, etc.
  • Encrypt
    • Pretty self-explanatory... A key possessing this capability can decrypt messages to it.
  • Sign
    • A key possessing this capability may create digital signatures of messages, showing incontrovertible proof that you wrote the message or possess the key. Often confused with certify because this capability doesn't sign other keys.
  • Authenticate
    • Least commonly used, this is used for authenticating your identity via a challenge-response protocol. Hence can be used as an SSH identity.

The reason why you've not really seen much about this in SSH is that the SSH signing capability is only a couple of years old. SSH was used exclusively for authentication to connect to a server, so key separation was not required. However, the newer versions of SSH do now support key separation with a separate key usage, and verification of them by ~/.ssh/.allowed_signers file.

It is clear that GitHub does support both authentication and signing keys, as per https://github.blog/changelog/2022-08-23-ssh-commit-verification-now-supported/, however, most people use the same key for both. This is made worse as the well known .keys features share a simple list of the authentication key of the user GitHub user, but the signing keys https://api.github.com/users//ssh_signing_keys returns a JSON object. IMHO, there is also an argument the authentication keys should be private between GitHub and the users, and instead they should only publically offer the signing keys, as others need to rely on them.

I personally would like to see the practice of not only signed git commits, but also signing code releases with PGP keys be moved toward using SSH signatures instead. However, GitHub's use of auth keys for singing is problematic, as it encourages users attempting to automate signature verification add their signing keys to their authentication keys.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment