OpenSSHによる二段階認証について ワンタイムパスワード編

こんにちは、sowawaです。

OpenSSHによる二段階認証についての続編記事です。

ワンタイムパスワード(One Time Password: よくOTPと略されます)とは、一回限りの使い捨てのパスワードのことです。認証するサーバ等との間で事前に共有が必要な情報は、 アルゴリズムにより様々ですが時間やカウンターをベースにしたものがよく利用されています。 最近では、様々なサービスで同じメールアドレスとパスワードの組み合わせで使い回されたことによって、 ひとつのサービスから流出したパスワードとメールアドレスを他のサービスに対する不正アクセスに頻繁に利用された結果、 重要な情報を扱う様々なサービスではOTPを利用したニ段階認証が導入されるようになりました。

多くの人がアカウントを持っているGoogleでは、Google Authenticatorと呼ばれるモバイル端末等で動作するOTP生成アプリケーションを提供しています。

これらのアプリケーションは、もうご存じの方もいらっしゃると思いますが、例えばGitHub, DropboxなどGoogleのログイン以外にも利用可能です。

この記事では、これを前回のOpenSSHの二段階認証と組み合わせてSSHによるログインでも利用可能にしてみましょう。

1
2
3
4
5
6
7
...

ChallengeResponseAuthentication yes

...

AuthenticationMethods publickey,keyboard-interactive

前回の記事ですでに二段階認証を導入済みであれば、 上記のようにAuthenticationMethodsChallengeResponseAuthenticationが設定されていると思います。

加えて一点確認していただきたい項目があります。

1
UsePAM yes

UsePAMyesになっていることを確認して下さい。 CentOS 7であれば、デフォルトでこの値は設定済みです。

もうお分かりかもしれませんが、PAMにOTPを組み込むことでOTPによる二段階認証を実現するのです。 PAMとは、Pluggable Authentication Modulesの略で、プラガブルな認証モジュールのことです。 Linuxなどの各種認証にはPAMが導入されており、ユーザによるカスタマイズが可能です。

PAMの設定を間違えると重大なセキュリティ上の問題を引き起こす可能性があるので慎重に行うようにしてください。 (今回も前回に引き続き間違ってログインができなくなる可能性があるのでご注意下さい)

それでは、今回のメインであるGoogle AuthenticatorのインストールとPAMの設定に移っていきましょう。 まず最初に注意して欲しいのですが、時間ベースのOTPを導入するためログインに用いるクライアントとサーバの時刻をある程度正確にしておきましょう。 NTP等で時刻合わせを行っておくのが好ましいですが、大幅に時間がずれていなければ問題ありません。 (大幅という表現だと、個人差がありそうなので端末の時間を確認して30秒から1分以上ずれている場合は修正してくださいね。 待ち合わせ時間などもそうですが、人によっては時間に対する感覚が異なるので注意が必要です。)

それでは、Google AuthenticatorのPAMモジュールをインストールします。

1
2
3
4
5
6
$ cd /usr/local/src
$ wget https://google-authenticator.googlecode.com/files/libpam-google-authenticator-1.0-source.tar.bz2
$ tar xjf libpam-google-authenticator-1.0-source.tar.bz2
$ cd libpam-google-authenticator-1.0/
$ make
$ sudo make install

次に自身のモバイル端末に以下再掲するGoogle Authenticatorのアプリケーションをインストールします。

以上でインストールは完了です。

sshでログインする各ユーザにGoogle Autenticatorの認証用のファイルを作成します。

1
2
$ sudo su - sowawa
$ google-authenticator

実行する以下のような出力が得られます。 いくつかの質問があるので適切に答えていきます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Do you want authentication tokens to be time-based (y/n) y
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/sowawa@localhost%3Fsecret%3DA3PS7OXQCA6YUNYN
Your new secret key is: A3PS7OXQCA6YUNYN
Your verification code is 715614
Your emergency scratch codes are:
  83979679
  50080085
  69862193
  31325266
  70915314

Do you want me to update your "/home/sowawa/.google_authenticator" file (y/n) y

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) y

If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y

今回は時間ベースのトークンを用いますので最初の質問はyと答えてください。 以降の質問も基本的にデフォルトのままで問題がないのですべてyと答えてよいでしょう。

この回答後に表示されたURLにアクセスするとQRコードが表示されます。 手持ちのモバイル端末にインストールしたアプリケーションから読み取ることができますが、 トークンが漏れだしてしまうリスクがあるのでURLやQRコードも含めて履歴等に残らないように細心の注意を払いましょう。 怖い人は直接端末にトークンを打ち込みましょう。

次はインストールしたモジュールを利用できるようにPAMを設定します。

/etc/pam.d/google-auth

1
2
3
4
5
#%PAM-1.0
auth        required      pam_env.so
auth        sufficient    pam_google_authenticator.so try_first_pass
auth        requisite     pam_succeed_if.so uid >= 500 quiet
auth        required      pam_deny.so

次に、既存の/etc/pam.d/sshdを以下のように編集します。

/etc/pam.d/sshd

1
2
3
4
5
6
7
8
9
10
11
12
13
#%PAM-1.0
auth       required     pam_sepermit.so
auth       substack     google-auth
account    required     pam_nologin.so
account    include      password-auth
password   include      password-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open env_params
session    optional     pam_keyinit.so force revoke
session    include      password-auth

先ほど作ったgoogle-authsubstackで呼び出しています。 substackinclude同様に外部ファイルを読み込みますが ファイル内で認証の成否が完結するものを読み込むときに利用します。 sshdでは元々password-authというファイルをsubstackで呼び出していたと思いますが、 これをgoogle-authに変更します。

設定は以上です。今回はsshdの設定を変更していないのでsshdの再起動は不要です。 くれぐれもログイン中のセッションを切断することを早まらず他のシェルやターミナルを用いて動作確認してみてください。

1
2
3
$ ssh gauth-host
Authenticated with partial success.
Verification code:

のように表示され、OTPの入力を求められることでしょう。 モバイル端末で表示されているOTPを入力するとsshでのログインに成功することと思います。

あとがき

今回は二段階認証にOTPを導入することが出来ました。 公開鍵認証とOTPの組み合わせでリモートログインへの不正アクセス対策はバッチリですね。 Google Authenticatorをインストールした端末を無くしたりするとログインできなくなるのでくれぐれも注意してください。

最後に、今回用いたGoogle AuthenticatorのPAMモジュールは、 使い方によってはログインやsudoの呼び出しにもOTPを利用することができます。 使い方次第で、あなたの認証環境に新しい可能性をもたらしてくれることでしょう。 OpenSSHをハックした次はPAMをハックしてOTPを使いこなしましょう!