SSH the secure way, with SSH keys

Reading Time: 8 minutes

TL;DR

(TL;DR) If you Google this sort of topic looking for the minimum commands needed to get it working, you simply need to generate a good key and copy it to the server. Below are those commands. (Code blocks with strikethough formatting are for illustrative purposes and should not be run.) Do consider reading the whole article, though, to better understand how to secure your connection.
To SSH without a password using SSH keys:
Generate a key pair:

$ ssh-keygen

You know, as long as we’re generating a key pair, let’s give it a more robust key than the default by specifying a byte length of 4096:
$ ssh-keygen -t rsa -b 4096

Copy it to the server:


$ ssh-copy-id you@remote.server

Introduction

In this post, I will walk you through the setup of SSH keys and their basic usage.
(For a simple overview of the technologies involved, visit the Public Key Cryptography page on Simple Wikipedia.)
The goal is to enable you to log in to a remote server without having to type your password each time, while increasing security and improving your ability to automate what you do.

Why not just stick with passwords?

People, when given the opportunity, pick terrible passwords, then reuse them irresponsibly. Even if you pick a decent (8-character NTLM,) password, as of 2012, it was possible to brute-force crack it in ~6 hours, using a fairly affordable computer.
You simply cannot brute-force an SSH key. The NSA might be able to, but any hacker looking to get in to a system is going to look for a different way to get in.
For this, you’ll need a computer running Linux, Windows, or OS X, as well as a server running an SSH server on which you have a login and password.
For simplicity’s sake, we will be doing everything from the command line, so if you’re on Windows, you’ll want to first install Git Bash. If you’re on a Mac, open up Terminal from your Utilities folder. (Yes, many people using Window prefer Putty, but configuring that is outside the scope of this document.)

Generating your key pair

When you have your terminal open, we’re going to generate what is known as an RSA key pair.

$ ssh-keygen -t rsa -b 4096

This command will ask you a few questions. For now, we’re going to simply hit `enter` and go with the defaults, as well as an empty passphrase. (More on that later.)
Generating public/private rsa key pair.
Enter file in which to save the key (/c/Users/User/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /c/Users/User/.ssh/id_rsa.
Your public key has been saved in /c/Users/User/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:RxUO7mLtlE3LSa1HrOJAkOJYg+JTzIHpZDvWIdR6Ws8 User@x230Len171025
The key’s randomart image is:
+- -[RSA 2048]- – +
|..*o. .. . o. |
|.*.*+ .. . + o |
|=.*+.o . o + + |
| O.+. . + * * |
|. * o S B B . |
| . E . B . . |
| o |
+- – -[SHA256] – -+


If everything worked and it generated that weird bit of ASCII art, we’re ready to move on to the next step:

Uploading Your Key

To be of any real use, you need to put your key somewhere. We’re going to upload it to the server. Let’s suppose that you are logging in to the host test.mmdc.net and your user name is jim.
We’ll first log in using a password:

User@x230Len171025 MINGW64 ~
$ssh jim@test.mmdc.net

If this is your first time logging in, you’ll be asked to confirm the server’s identity:


  $ ssh jim@test.mmdc.net
The authenticity of host 'test.mmdc.net' can't be established.
ECDSA key fingerprint is SHA256:u6fDHy25AXJD3MWXLkjhgkjhgLOjoBdZQOoQCZXBI.
Are you sure you want to continue connecting (yes/no)?

Type “yes”. (More on this later.)


  Warning: Permanently added 'test.mmdc.net' (ECDSA) to the list of known hosts.
jim@test.mmdc.net's password:

Type your password and hopefully you are now greeted with your remote prompt:


jim@test.mmdc.net:~$

Very good! Now log out, using Ctrl-d.
Back at your local terminal, we’re going to copy your key to test.mmdc.net:


$ ssh-copy-id jim@test.mmdc.net

This will (hopefully) give you output similar to the following:


/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/c/Users/User/.ssh/id_rsa.pub"
The authenticity of host 'test.mmdc.net (23.189.0.8)' can't be established.
ECDSA key fingerprint is SHA256:u6fDHy25AXJD3MWXLi9Up2rmDp2LOjoBdZQOoQCZXBI.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
jim@test.mmdc.net's password:

Number of key(s) added: 1

Now try logging into the machine, with: "ssh 'jim@test.mmdc.net'"
and check to make sure that only the key(s) you wanted were added.

Give it a try:


$ ssh jim@test.mmdc.net

If everything went as it should have, you’ll be now logged in to the remote machine, without having been asked for a password. Pretty cool, eh?
How can we make it better?

Customizing your SSH Config


When we created the SSH keys, it stores them by default in a hidden directory in your home directory, called ‘.ssh’ where we can put a special file called ‘config’ that can hold some very useful configuration options.
Let’s edit the config file. (You may need to create it, but when you do, it will be instantly activated, as long as it’s in the correct directory.)
What would we want in this file? Keeping our example above in mind, we might add the following directives for this host:

host test.mmdc.net test web1 
HostName test.mmdc.net
User jim
Port 22
ServerAliveInterval 120

The first line defines a bunch of aliases for this host, any of which can be used, like:

ssh test

would be the same as typing:

ssh test.mmdc.net -l jim -p 22

(Yes, port 22 is the default, so explicitly specifying it may seem superfluous, but I’ve added it for when you want to specify a non-standard port.)
On my Windows laptop, I never changed from the user called “User,” so if I don’t specify a different user, that’s what it will try to log in with, so I specify “jim” in the config.

Next Steps

If you’ve gotten this far, you are well on your way, but there are things you can do to make your connection even more secure. Let’s get started:

Add a PassPhrase

First off, you need to have a good passphrase for your key. (Wait? What? Wasn’t the whole point of this to get away from passwords?)
The point of having a passphrase to encrypt your private key is to protect your key if your laptop is lost or stolen, or you lose track of an old backup. Without a passphrase, whoever has this key can log in whereever the key has been authorized.
The convenience of a password-free login has a great deal of appeal, which is SSH.com reports that “More than 90% of all SSH keys in most large enterprises are without a passphrase.”
If you have a key that doesn’t have a passphrase, it’s easy to add one:


$ ssh-keygen -p
Enter file in which the key is (/c/Users/User/.ssh/id_rsa):
Enter new passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved with the new passphrase.

By default, SSH will ask you for this passphrase every time you invoke the key, something that gets tiresome quite fast. Fortunately, there is a way to minimize the inconvenience:

SSH Agent

SSH Agent is a program that will ask you once at the beginning of your session for your passphrase and cache it for the length of your session
You can run it manually


$ eval $(ssh-agent)

Having to put “eval” in the command has led to a lot of frustration and misunderstanding about ssh-agent. After all, running ssh-agent alone doesn’t seem to raise an error, but doesn’t do what we need:


$ ssh-agent
SSH_AUTH_SOCK=/tmp/ssh-dHKgccDFLL7z/agent.14536; export SSH_AUTH_SOCK;
SSH_AGENT_PID=5588; export SSH_AGENT_PID;
echo Agent pid 5588;

What’s happening is that ssh-agent is generating some environment variables, but ssh-agent cannot evaluate them for the parent process, (it’s a Unix security issue,) so we must call ‘eval’ explicitly.
Next, we must add our key to the agent:


$ ssh-add ~/.ssh/id_rsa

Believe me, this is *not* something you want to have to do every time you want to get some work done, so let’s script it all to run automatically at login.
On your workstation, open up your .bash_profile (for Git Bash on Windows, create a file called “.bashrc” in your home directory,) and add the following to the end of the file:


SSH_ENV="$HOME/.ssh/environment"

function start_agent {
echo "Initialising new SSH agent..."
/usr/bin/ssh-agent | sed 's/^echo/#echo/' > "${SSH_ENV}"
echo succeeded
chmod 600 "${SSH_ENV}"
. "${SSH_ENV}" > /dev/null
/usr/bin/ssh-add;
}

# Source SSH settings, if applicable

if [ -f "${SSH_ENV}" ]; then
. "${SSH_ENV}" > /dev/null
#ps ${SSH_AGENT_PID} doesn't work under cywgin
ps -ef | grep ${SSH_AGENT_PID} | grep ssh-agent$ > /dev/null || {
start_agent;
}
else
start_agent;
fi

.bash_profile is for Bash, of course. For other shells, you’ll need to find its ‘.profile’ equivalent. If, like me, you use Robby Russel’s excellent Oh My Zsh, there’s a plugin for ssh-agent.
When you have that all configured, reboot your workstation if you can, to properly test.
Open a terminal, ssh to your favorite host, enter the passphrase when prompted, hopefully for the only time this session.

Entropy

To be truly secure, you need a good source for entropy. People have gone to great lengths to devise random number generators, but for our purposes, we’re going to look at the two built in to a Unix-like system: /dev/random and /dev/urandom.
There are a lot of differing opinions on which you should use. /dev/urandom is the default and it’s arguably a good choice, but if you’d like to use /dev/random, you can do that by setting an environment variable before generating your key:


$ export SSH_USE_STRONG_RNG=64

As long as we’re being paranoid, let’s now generate a *huge* key, the largest currently allowed:


ssh-keygen -b 16384

That will take some time, probably a minute or two on a typical home computer, but back in 2004, it would have taken days.
So, should you use a huge key? Perhaps, for bragging rights, if you happen to have friends who would understand what you are talking about, but you’d probably be looking at diminishing returns.

Verifying the Server

What good is any of this, if you cannot know for certain that the server you are talking with is not, in fact, who it says it is?
Remember, above, when we were told “The authenticity of host ‘test.mmdc.net’ can’t be established“? Well, it *is* possible to verify the server’s identity absolutely, but to do so properly, you need to have someone logged *directly* in to the server. Sitting in front of the actual machine, on an attached console or KVM, *not* using SSH to connect.
That person should run the following commands to extract the key signatures: (More on this.)

cd /etc/ssh
for file in *sa_key.pub
do ssh-keygen -lf $file
done

Ideally, this should be done after the SSHD daemon is installed from trusted media, but before the machine is connected to the Internet.
Those signatures should then be printed, signed, notarized, copies made, those signed and the originals placed in an envelope that is sealed with a wax seal and placed in a bank vault deep in the Swiss Alps.
OK, perhaps that last bit is excessive, but how much do you need to be sure that your connection has not been compromised? Having the signatures printed off at install time would be a good idea, as well as having humans involved in the verification process would not be out of line if your organization uses these connections to deal with sensitive or valuable information.

Disable Password Login

Finally, when you are comfortable that you’ve done everything correctly, gotten your keys created, tested and backed up somewhere safe, it’s time to disable password logins completely. Be sure to do this only on a server that you have physical access to, so you can plug in a keyboard and monitor if you screw something up.

$sudo vi /etc/ssh/sshd_config 

Find the directives below in that file and change each of them to “no”:

ChallengeResponseAuthentication no
PasswordAuthentication no
UsePAM no

When that’s completed, restart the SSH server:

 $ sudo service ssh restart 

The great thing about SSH, as you have seen here, is that it will rise to the challenge of verifiably securing your data in transit, while staying fairly simple and unintrusive, after just a bit of configuration.

Thanks

Thanks to the following Reddit users for reading this, pointing out errors and omissions and generally challenging me to write an article worth reading:

/u/gandalfx
/u/tdk2fe
/u/mk_gecko
/u/harryruhr
/u/thread-safe
/u/stormnet
/u/maybe_born_with_it
/u/krs013
/u/beachbum4297
/u/rubdos
/u/joelparkerhenderson
/u/farverio
/u/researcher7-l500

The Voice Kit is *not* a Google Home in kit form

Reading Time: 3 minutes

(Update: Please visit the AIY SubReddit!)
Yesterday morning around this time, I read the announcement of the new kits from Google and got pretty excited. The Google Voice Kit got an upgrade and now includes a Raspberry Pi WH model along with all the other hardware you need to put this together. They also released something called a Vision Kit that does some pretty cool image processing. (No doubt I will get one of those as well, but for now, there are things I want to try with the Voice Kit first.)

The hardware build was pretty simple, but there are places where you need to have the instructions, such as assembling the speaker’s wire harness. Do yourself a favor and follow the instructions. The cardboard case, in particular, should be done in a certain manner, as to not have it look like garbage when you have completed it.

So, I got the thing all together and booted it. The green LED on the Pi flashed and everything looked good. I ran the Android app and pushed the buttons as directed and… Nothing. I rechecked all of the connections and rebooted and again, nothing. The next step was to get a monitor and keyboard hooked up to it to see what was going on with it. The thing is, it has a Mini HDMI connector and Micro USB, unlike the other Raspberry Pi’s I’ve used. That means you need some special connectors and micro USB OTG cable and some way to get both a keyboard and mouse connected to the one micro USB, all which I fortunately happened to have and was somehow miraculously able to find.

I rebooted the device and it went to a black console screen with small Raspberry and a flashing cursor. It didn’t display the familiar rainbow square that my other Pi’s do and there was no scrolling of boot messages. I figured that the card’s image had probably gotten corrupted, either in transit, or by something I did after assembling it. (I probably powered it down at a bad point.) The thing is, there’s no way of knowing without a monitor connected.
I found the help section on the AIY website that has a link to the disk image, a modified Raspbian image. I downloaded that and flashed it to the card and rebooted with the monitor, mouse and keyboard connected.

This time, it worked and it displayed a Raspbian desktop. I pushed the big white arcade button on top, expecting to hear a familiar Google Home chime or a voice or something, but, again, it did nothing. Back to the instructions.

At this point, I had the hardware correctly assembled and configured and the software running and connected to my WiFi. It is time to start enabling the Google end of things, something which requires using the command line, either via SSH or on the Pi directly, using Raspbian’s console. Don’t worry if you’re not familiar with the command line–the instructions are clear and written with a beginner in mind. The section “Get Credentials” will probably be new and unfamiliar territory, if you are not a developer, familiar with API’s and all of that. Again, the instructions are clear and straightforward, though complex. Read them carefully.

When that’s all done, find Step 90, “Move to the demos folder” and type the commands as instructed to run the demonstration program. Running the demo, you really will want to keep an SSH session open, so that you can see what’s happening. Without it, there is simply too little feedback to be of use.

Is it a fully-fledged Google Home at this point? No. It doesn’t have any “Hey Google” listening capability. It can’t play or stream music yet. It does’t do *anything* if you just boot it up with a factory configuration.

Am I disappointed? Not at all. What this thing does give you is potential–it’s as hackable as any Raspberry Pi, with some cool new hardware. It’s got Python and some custom libraries that will let you do things that you could never do with a Google Home, such as experiment with its GPIO pins, or perhaps make it the interface for a completely different piece of hardware: “Google, preheat the oven to 425 degrees and then bake for an hour. Reduce the temperature to 300 degrees and bake for 20 minutes. Send me a text when it’s done.”

I’ll be writing more about what this thing can do, here and on Reddit’s AIY sub, but for now, I’m going to go hack around with it to find out.

jrnl, a Command Line Journal

Reading Time: 1 minute

There are few things more satisfying than using a well-made tool. ‘jrnl‘ is one of them–a simple, well-made program for taking notes and journal entries, so well-written that it feels like a native Unix utility.

Creating an entry is simple:

$ jrnl This is a journal entry. It will be automatically date-stamped
 [10:18:44] [Journal created at /home/jim/journal.txt]
 [Entry added to default journal
]

It creates a simple text file:

$ cat journal.txt

[10:18:52] 2018-03-09 10:18 This is a journal entry.
It will be automatically date-stamped


If you wanted to create an entry for something in the past or future, it’s simple: (jrnl keeps them sorted by date, too!)

  $ jrnl at April 1, 1918 4:10AM: I was Born
 [10:20:09] [Entry added to default journal]

jrnl doesn’t use a proprietary format,  just a simple text file, so you can edit it and read it with anything.

You’re not limited to raw text, though.  You can export to a variety of formats. Here’s JSON:

$ jrnl --export json                                                                                                                                        [10:54:46] {
 "entries": [
 {
 "title": "I was Born",
 "date": "1918-04-01",
 "time": "04:10",
 "body": "\n",
 "starred": false
 },
 {
 "title": "This is a journal entry.",
 "date": "2018-03-09",
 "time": "10:18",
 "body": "It will be automatically date-stamped\n",
 "starred": false
 }
 ],
 "tags": {}
 }

Installation is easy, if you have Python and PIP installed and configured:

 pip install jrnl

jrnl- The Command Line Journal

jrnl- The Command Line Journal

jrnl has a natural-language interface so you don’t have to remember cryptic shortcuts when you’re writing down your thoughts.

Source: jrnl.sh/

Hello, Again

Reading Time: 1 minute

Hey there. 
It’s been a while.
How’ve you been?

I’ve been good, I guess. Still in the US, still in PA.

And now after years of hiatus, again taking a stab at blogging.
Back when I started blogging, before anyone even called it that, I used to hand-edit my site in vim or notepad and change the top page as stuff happened.
Later, around 2003 or so, I started using MovableType, then later WordPress and it seemed like blogs were the most important form of communication imaginable. Back then, I could take a picture somewhere on the streets of Tokyo, where I was living, post it to my site , and within a day, a couple thousand people had seen it.
That was cool, but I don’t expect to ever see those kinds of stats again.
(Anyone else remember Daypop‘s top 40? Get on *that* and you’d be up all night trying to keep your server from crashing under the load.)

RSS was new and shiny and did for sites what Facebook and Reddit do now with your content, but without keeping your eyeballs glued to their own ads. Some of you still use RSS readers, I see, while I was setting up this site today and ‘tail -f’ing access logs, I saw a couple of hits from news readers. They inspired me to write this post, actually.

If you look up at the URL of the site, you’ll see I finally got around to moving to HTTPS, using the very excellent Let’s Encrypt. I take it that browsers are going to start calling you out if you don’t encrypt, so I might as well, I guess.

Well, I’m going to get going for now. If you happen to see this, leave a comment below.