Двухфакторная аутентификации ssh при использовании пароля или публичного ключа


Одноразовые пароли, при своей кажущейся простоте, весьма эффективны и все больше набирают популярность. И действительно, даже сложный постоянный пароль можно взломать или перехватить. Реализовать двухфакторную аутентификацию можно, например, посредством sms или приложения поддерживающего стандарты TOTP или HOTP, разработанные сообществом OATH. Рассмотрим применение последнего к авторизации по в связке с Authenticator.

Для начала некоторые подготовительные мероприятия. Для работы нам понадобится установить пакеты:

root@:~# apt-get install libpam-google-authenticator libqrencode3 ruby rubygems
root@:~# gem install rotp

Сгенерируем ключ для авторизации суперпользователя без пароля

[email protected]:~# ssh-keygen -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
b9:2d:95:8b:b1:94:c9:61:75:71:7d:5c:31:15:fb:1a [email protected]
The key's randomart image is:
+--[ RSA 4096]----+
|          . o..*B|
|         . . .  *|
|        o      ..|
|       o = .    .|
|        S o   E .|
|       . B .   o |
|        = o   .  |
|         .       |
|                 |
+-----------------+

И разрешаем аутентификацию по этому ключу

[email protected]:~# cat .ssh/id_rsa.pub > .ssh/authorized_keys

К аутентификации по публичному ключу вернемся позже, сначала поговорим про парольную аутентификацию.

Приведем конфигурационный файл /etc/ssh/sshd_config к виду

PermitRootLogin without-password
RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile      %h/.ssh/authorized_keys
ChallengeResponseAuthentication yes

Создаем группу google_auth и добавляем в эту группу пользователей, которые будут использовать libpam-google-authenticator.

[email protected]:~# groupadd google_auth
[email protected]:~# usermod -a google_auth rascal

Теперь необходимо настроить , для этого добавляем в файл /etc/.d/sshd

# Google Two-step verification
auth [default=1 success=ignore] pam_succeed_if.so quiet user ingroup google_auth
auth required pam_google_authenticator.so

Перезапускаем ssh сервер

[email protected]:~# service ssh restart

Для настройки окружения пользователя необходимо выполнить:

[email protected]:~# google-authenticator

В результате работы этой утилиты вы увидите QR-код, который можно отсканировать в приложение Google Authenticator на ваш смартфон:
google-authenticator

Двухфакторная аутентификации при использовании для аутентификации пароля теперь работает, при следующей попытке зайти на сервер по ssh происходит запрос «Verification code».
А вот при авторизации при помощи публичного ключа вы этого запроса не увидите. Дело в том, что openssh при успешной авторизации с использованием публичного ключа не инициализирует PAM, а значит libpam-google-authenticator не работает.
Тем не менее, есть обходное решение в виде ruby-скрипта от moocode, сохраняем его как /usr/local/bin/two_factor_ssh

#!/usr/bin/env ruby
require 'rubygems'
require 'rotp'
# we'll pass in a secret to this script from the authorized_keys file
abort unless secret = ARGV[0]
# prompt the user for their validation code
STDERR.write "Enter the validation code: "
until validation_code = STDIN.gets.strip
sleep 1
end
# check the validation code is correct
abort "Invalid" unless validation_code == ROTP::TOTP.new(secret).now.to_s
# user has validated so we'll give them their shell
Kernel.exec ENV['SSH_ORIGINAL_COMMAND'] || ENV['SHELL']
[email protected]:~# chmod +x /usr/local/bin/two_factor_ssh

Добавляем в конфигурационный файл /etc/ssh/sshd_config

Match User root
ForceCommand /usr/local/bin/two_factor_ssh QKRBILHQ6U3PSZHT

Перезапускаем ssh сервер

[email protected]:~# service ssh restart