Skip to content

Instantly share code, notes, and snippets.

@ifalldev
Created October 15, 2017 22:28
Show Gist options
  • Select an option

  • Save ifalldev/45c2286573966f5a0984e6f1f9cd380d to your computer and use it in GitHub Desktop.

Select an option

Save ifalldev/45c2286573966f5a0984e6f1f9cd380d to your computer and use it in GitHub Desktop.

Revisions

  1. @ColinStein ColinStein created this gist Feb 15, 2016.
    260 changes: 260 additions & 0 deletions creating_keys.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,260 @@
    # Creating Keys
    This is a brief guide to creating a public/private key pair that can be used for OpenSSL.
    While the "easy" version will work, I find it convenient to generate a single PEM bundle
    and then export the private/public key from that as needed. This document also covers how
    to add and remove a password from your private key and how to make sure that keychain
    will automatically unlock it when you sign in.

    ## Just make it work
    Generate an ssh key-pair:

    $ ssh-keygen

    If you just pound enter through the setup procedure then you will end up with a new key
    pair created in the default location: `/Users/yourname/.ssh/`. There will be two files:

    * `id_rsa` This is your private key, you must keep it secret and never allow anybody
    else to gain control of it. Treat this key like a password, keep it safe and make
    a backup copy. You can add it to keychain using `ssh-add -K ~/.ssh/id_rsa`.

    * `id_rsa.pub` This is your public key, you can share it freely. This part of the key
    is used during authentication to encode a message which can only be decoded with the
    private key. It cannot be used to derive the private key so there is no risk in
    sharing it.

    When a server administrator asks for a copy of your public key, send them a copy of the
    `id_rsa.pub` file. They'll be able to add it to your user account's list of authorized
    keys and that will enable you to log in without typing a password.

    ## Doing it the hard way
    This method involves creating the keys as a bundle, exporting the public key and
    manually setting the permssions on all of the paths. You'll also have to configure
    OpenSSH to use your new bundle for authentication.

    A summary of the steps follows:

    $ mkdir ~/.ssh
    $ chmod 0700 ~/.ssh
    $ cd ~/.ssh
    $ openssl genpkey -algorith RSA -aes-256-cbc -outform PEM -out yourname.pem \
    -pkey_opt rsa_keygen_bits:4096
    $ chmod 0400 yourname.pem
    $ ssh-keygen -y -f yourname.pem > yourname.pub
    $ chmod 0444 yourname.pub

    ### Rational
    I prefer to generate a certificate using OpenSSL directly, then export the private or
    public-key in the necessary format as needed. The benefits to this appraoch are three-
    fold:

    1. This is a process similar to the one you'd use to generate certificates used for
    other tasks like S/MIME or to become part of a signed certificate for HTTPS.
    2. There is a single certificate file from which you can derive the private or public
    key in whichever format you need. It's much easier to manage one key than two, or
    even several if you require the key in different formats.
    3. You gain control over the key length, encryption method, and algorithm so that you
    can consciously decide to use weaker keys for old/slow hardware (e.g. the Raspberry
    Pi media server in your closet) and strong but slower keys where appropriate.

    ### Default software and Mac OS X
    In order to generate the key I prefer to use OpenSSL directly rather than the ssh-keygen tool.
    While it is possible to provide flags to `ssh-keygen` using OpenSSL gives us access to options
    that are not avaiable in the standard Mac OS X version of SSH but doesn't require us to build
    the SSH client from scratch.
    #### Update OpenSSL
    Unfortunately the version of OpenSSL that ships with Mac OS x is rather dated and so it's
    missing some of the features of the latest versions. One of those features is the `genpkey`
    command which is the new recommended way to generate keys. Assuming you have Homebrew
    installed (see: https://brew.sh) you can install an up-to-date version of OpenSSL with:

    $ brew install openssl
    $ brew link openssl --force

    Many packages that you install with homebrew are likely to depend on OpenSSL anyway so this
    is not a terrible idea even if you don't care about using OpenSSL directly.

    #### Updating OpenSSH
    If you're interested in rebuilding openssh you should link against LibreSSL so
    that passwords can be installed in your keychain.

    $ brew install openssh --with-libressl

    This is a relatively new option and caution should be taken because compatibility
    may not be perfect. LibreSSL is not intended to be a 1:1 replacement for OpenSSL.

    It appears that just building OpenSSH will not have it request key information from
    the Mac OS X keychain, nor will it automatically start SSH-Agent so there may be
    some trouble-shooting steps required if you prefer to go this path. I do not build
    a new version of SSH.

    ### Creating directories
    OpenSSH requires that keys be stored in `~/.ssh` and that path must be restricted
    so that only the user can access it. It also requires that any identify files be
    accessible only by the user too. Permssions for `~/.ssh/config` can be more relaxed
    but it is good practice to keep those private so as not to leak inforamtion about
    user names or servers you connect to.

    Create the directories by running:

    $ mkdir ~/.ssh

    While this will create the directory you will have to modify the default permissions.
    Read/write/execute for the owner and no access for any other user is required. Recall,
    the execute flag on a directory allows you to view its content.

    $ chmod 0700 ~/.ssh

    You might want to create an empty ssh config file and set appropriate
    permissions so that you don't have to remember how to do it later when
    there's some problem and you are half-asleep, drunk, and responding to a
    PagerDuty alert.

    $ touch ~/.ssh/config
    $ chmod 0600 ~/.ssh/config

    You can save a few copy steps if you're following this guide by changing
    into your ssh path for the remaining steps:

    $ cd ~/.ssh

    ### Generating keys

    The first step to generating keys is to create the bundle using OpenSSL. This
    approach allows us to specify a few extra options when creating keys that are
    normally hidden by `ssh-keygen`:

    $ openssl genpkey -algorith RSA -aes-256-cbc -outform PEM -out yourname.pem \
    -pkey_opt rsa_keygen_bits:4096

    The options: are

    * `genpkey` is the new command for generating keys, it supercedes the old
    `genrsa` method. Mac OS X's default OpenSSL does not have this command so
    building your own version is required.
    * `-algorith rsa` uses the RSA algorithm for the key and is recommended for
    maximum compatibility. Other options include `ECDSA`, which is less
    computationally intensive on very low-end hardware (e.g. 50 MHz ARM) and
    `DH` which has characteristics similar to RSA but is rarely used.
    * `-aes-256-cbc` is the cypher used to encrypt the bundle and causes the user
    to be prompted for a password. There are a number of available ciphers but
    AES-256-cbc is among the stronger options available and widely used too.
    * `-outform PEM` there are several output formats that you can use but PEM is
    widely used by open source software and tends to be the best supported. The
    format is also nicely encoded so that you can debug with any text editor and
    has the advantage of bundling the public and private key into a single file
    which makes them easier to move around. You can always output the public or
    private key from a PEM bundle that contains both.
    * `-pkey_opt …` can be specified multiple times and supplies options to the
    generation function. This can be specified multiple times to suplly several
    options

    * `rsa_keygen_bits:4096` sets the length of the keys produced. 1024 bits is
    generally considered the absolute minimum for secure communication today
    though there is some concern that they will be broken for well-funded
    attackers in the near future so 2048 bits is recommended where possible.
    Longer keys provide greater security however there is diminishing returns
    as key length increases. Also, increasing the key length also increases
    computational costs exponentially (by the cube of the change, so 2048 is
    8x more demanding than 1024-bit). You may want to use smaller keys for
    slower hardware or if you find yourself frequently reconnecting due to bad
    connections during a session for better performance.

    * `-out yourname.pem` defines the output file for your bundle. You should store
    a copy of this certificate in `~/.ssh` so that it can be used to authenticate
    ssh sessions. The file must not be accessible to other users on the system so
    set the permissions accordingly. You should also store the file and the
    password somewhere safe (like in your password vault or on a USB drive in a
    safe deposit box).

    When generating the key you will be prompted for a password. Make sure to use a very
    strong, unique, random password for this file. You won't have to type it in regularly
    so generate it with your password vault. In a pinch you can generate a random password
    using OpenSSL via: `openssl rand -base64 48`.

    When the bundle has been generated, copy it to your`~/.ssh` folder and change its
    permissions accordingly:

    $ cp ./yourname.pem ~/.ssh/yourname.pem
    $ chmod 0400 ~/.ssh/yourname.pem

    I prefer to make the bundle read-only for my user so I never accidentally edit it or
    strip the password. `chmod 0600 ~/.ssh/yourname.pem` would also work if you don't mind
    it being editable by your user.

    ### Extracting the public key
    You'll want to be able to send the public key to other people and leave it on other
    computers without risking your private key. The easiest way to export your public
    key is using the ssh-keygen method which prints it to standard out.

    $ ssh-keygen -y -f yourname.pem

    You can always redirect that to a file if you want to send it via email or copy it
    via SFTP. Generally I prefer not to keep a copy of my public keys on disk so that I am
    justified in always treating `~/.ssh` as a secret.

    ### Configuring OpenSSH
    Remember to either edit your `~/.ssh/config` to specify this bundle as the default
    identify file by adding the line:

    IdentityFile ~/.ssh/yourname.pem

    Alternatively you can specify it on a host-by-host basis by using ssh command-line
    options: `ssh -i ~/.ssh/yourname.pem example.com -l someuser`. When you are
    prompted for a password, remember that you should enter the one used when creating
    the bundle, not the log-in password for your computer or the remote system you are
    connecting to.

    Finally, you should consider adding the key to your Mac OX X keychain using:

    $ ssh-add -k ~/.ssh/yourname.pem

    This will store the password in the login Keychain which is unlocked automatically
    whenever you sign in. Storing your password this way means you won't have to re-type
    the password you used when creating the bundle in order to use it.

    Using `ssh -i ~/.ssh/yourname.pem foo.example.com` will also add your key to Keychain.

    ## Public Keys and Github.com
    It's a good idea to add your public key to github.com so that you can pull from private
    repositories and push changes to your public repositories. You can do this at:

    https://github.com/settings/ssh

    Once you've uploaded your **public** key, other users can download it by going to

    https://github.com/yourusername.keys

    For example, my public key is located here: https://github.com/colinstein.keys

    You may want to create different key-pairs for different repositories or organizations
    and then use `~/.ssh/config` and local `.gitconfig` files ot manage those relationships.

    After generating keys in the above manner for each github account you can configure
    ssh by editing `~/.ssh/config` and adding entries like the following for each account:

    # Foo Account
    Host github.com-foo
    HostName github.com
    User git
    IdentityFile ~/.ssh/foo.pem
    # Bar Account
    Host github.com-bar
    HostName github.com
    User git
    IdentityFile ~/.ssh/bar.pem
    When cloing a repository you would then clone from the appropriate host:

    $ git clone [email protected]:somegithubuser/somerepo.git


    You can also edit the existing git remote by editing the `.gitconfig` inside
    the checked out repository:

    [remote "origin"]
    url = [email protected]:somegithubuser/somerepo.git

    Git also provides a number of ways to configure SSH via `git config` and
    `git remote add foo [email protected]:somegithubuser/somerepo.git`. A full
    run through of those options is well outside the scope of this gist.