Edit2: It's worth pointing out that both those scripts were written fairly quickly by me, for basic personal use. If you want to use them I would recommend going through them and making sure I didn't screw anything up.
These are much more sensible that the OP's solution.
Just to be clear to anyone reading, because it's not really explained:
* OP double-protects the SSH key. It means you need the key's passphrase and another factor (Google authenticator) to decrypt the ssh key. Then the ssh key is used to auth with the server.
=> the authentication with the server is still one factor auth, compromising the key at any level still grants access.
=> obligatory analogy: OP did like that: put your car key in a box that also has a key. Attacker just need a copy of the key in the box to open the door (granted that he won't use any physical attack on the door :p)
=> 2 (or more) factor authentication should always be used on the component that does the final authentication.
* People using ForceCommand apply the 2 factor at the last step of authentication, that is, once the ssh key authenticated you correctly, you still need to authenticate to something else before being given access.
=> obligatory analogy: now you have a key and a cellphone. you turn the key in the car and the door doesn't fully unlock. you gotta enter a code given by the cellphone before it actually opens. if the attacker get a copy of your key, it's not enough. if the attacker gets a copy of your phone's passcode (even thus it changes each time), its not enough.
"* OP double-protects the SSH key. It means you need the key's passphrase and another factor (Google authenticator) to decrypt the ssh key. Then the ssh key is used to auth with the server.
=> the authentication with the server is still one factor auth, compromising the key at any level still grants access."
This is not correct. You can't decrypt a key with a one time password.
The OP is requiring a the second factor(the OTP) after the key is sent to the server and authenticated.
Not only does it allow you to do it globally, it doesn't allow a user to log in and disable it on you either. If you have to have them turn it on in ~/.ssh/authorized_keys all it takes is someone to get in once to add in a key that doesn't require that any more.
It's the I'd of your specific Yubikey - I'm on my phone on a train right now, but off the top of my head it is the first 12 characters that get printed when you use your Yubikey. Pretty sure it's 12, anyway.
If you're running a recent version of OpenSSH, you can add the 'ForceCommand' param to sshd_config to add it for all users. The only downside to this is it is for all users, so if you run something that needs to use key based login without the two factor method you'll need to validate that yourself within the script.
it seems to me that you're doing 2 factor on the ssh key decryption. That's not so useful IMO from the security point of view.
The factor should be an alternative to the ssh key itself aka server side aka via ForceCommand as suggested
A while back I wondered how hard it would be to integrate two-factor authentication on a web site using Google's Authenticator app, since it uses open protocols and is available on all platforms. Turns out it's incredibly easy. Even made a demo: http://dendory.net/twofactors/
I was using the command="" stuff to restrict a user to only running rsync the other day and was considering writing the script in ruby as was done here. Does anyone have any opinion on how safe that is? The client shouldn't have that many ways to interact with the ruby process but I was still wondering if I should stick to something smaller like /bin/sh (not even bash) for safety.
Right, that was what I asked in my other post. I assumed sshd would fill in the login shell there if nothing was passed as that is effectively what is being called but it seems not. I see you're doing exec(SHELL) to fix that.