水深1024m

技術的なメモとか日記的なもの

触って試す AWS MFA

相次ぐパスワードリスト攻撃もあり、いわゆる MFA (Multi-Factor Authentication) が使えるサービスが増えてきました。 AWS でもデバイスによる MFA ができるようになっています。 この仕組みとかについて書きます。 AWS について主に書いていますが他のサービスで使われているものも大体同じ (少なくとも GitHub とかは) はずです。

AWS MFA で使われている仕組み

IAM の FAQ でも書かれていますが、 AWS で使うことができるのは TOTP (Time-based One-Time Password Algorithm) です。 アルゴリズムの説明は こちら などがわかりやすかったです。 TOTP の RFC もそんなに分量ないので読んでみると良いと思います。 ざっくり言うと TOTP がしているのはすごく単純なことで、

  • 認証を行う側と認証される側で同じ鍵を共有しておく
  • お互いが同じ鍵を用いて同じ計算方法でワンタイムパスワードを生成する。生成時、変化する要素として現在時刻が使われる

これだけです。鍵の共有時を除けば認証する側とされる側で通信する必要がないので、 スマートフォンを MFA デバイスにしている場合それがオンラインである必要はありません。

ちょっとコード書くとその様子を眺めることができるので後述します。

ハードウェア MFA とバーチャル MFA

AWS の MFA ではハードウェア MFA デバイスとバーチャル MFA デバイスの2種類が使えるようになってます。

ハードウェア MFA

AWS の場合、ハードウェア MFA は専用のベンダーが一社あり ここ から購入します。 現在は小さい USB メモリみたいなものとカード型のものを選ぶことができますが、 カード型の方は日本から買えないようです。無念。

ベンダーのページに記載されていますが、これらも Time-based との記載がありますので TOTP が使われているものと思われます。 使っているアルゴリズムは同じですが、ハードウェア MFA とバーチャル MFA の違いは鍵の共有方法にあります。 若干推測ですがハードウェア MFA の場合、ベンダーはハードウェアのシリアルナンバーとそれに紐づく鍵を何らかの安全な方法で AWS 側に渡しているはずです。 そのため、このハードウェアを購入して AWS アカウントに使おうとすると、シリアルナンバーを入力するよう求められます。 このシリアルナンバーは実際の生成に使われるわけではなく、入力するとそれに紐づく鍵が AWS 側で呼び出されて、 以降その seed を元にワンタイムパスワードを計算するようになるという仕組みです。 また、このハードウェアには耐タンパー性がありますので、外から鍵を盗みとられるという可能性も少ないと思います。

バーチャル MFA

ハードウェア MFA の他にバーチャル MFA を選択することもできます。多くの人はこちらを使っていると思います。 バーチャル MFA の場合もパスワードの生成方法はハードウェアと全く同様ですが、スマートフォンアプリ (Google Authenticator, Amazon MFA) など 専用ハードウェアではないものの上で生成を行うところが差異です。 また鍵の共有方法も違います。ハードウェア MFA の場合鍵は予め AWS 側に渡っていますが、 バーチャル MFA の場合 AWS 側で生成した鍵を手元のデバイスで受け取る必要があります。 手段は多くの場合2通りで、QR コードを使うか鍵を手で入力します。

QR コードには、アカウントの名前や鍵, 認証の種類 (TOTP or HOTP) が含まれています。 Google Authenticator の wiki に詳しい説明が載っているので興味のある方はご参照ください。

キーを手動で入力する場合は、アカウントの名前などは情報として含まれないため手動で入力する必要があります。 また、鍵が格納されるのは結局スマートフォン上の記憶領域なので、その安全性はそのアプリや端末のセキュリティレベルによるというところが ポイントかと思います。

自分でやって観察してみる

ruby だと ROTP という gem があって、この OTP 周りの処理をやってくれます。 コード読んでみると実際どういう処理をやる必要があるのか見えてくると思います。 https://github.com/mdp/rotp

require 'rotp'
key = ROTP::Base32.random_base32
totp = ROTP::TOTP.new(key)
puts key
puts totp.now

こんなコードを書くと、16文字の base32 で生成されたキーと、それを元に生成したパスワードが返ってきます。

$ ruby rotp.rb 
amxz5qyc54sap3qp
271576

ここで生成されたキーを Google Authenticator に入力してみます。 サービスを新規追加する画面から、手動で入力 を選択し、アカウント(適当な名前) とキー (生成されたキー) を入力します。 時間ベース (TOTP) にチェックが入っていることを確認して完了ボタンを押すと、他のサービスに並んでパスワードが表示されると思います。

では、コード側でも生成されたキーでパスワードを生成するようにしてみます。

require 'rotp'
totp = ROTP::TOTP.new("amxz5qyc54sap3qp")
puts totp.now

これで totp.now を watch -n 1 とかで Google Authenticator といっしょに眺めてみると、 お互い大体同じタイミングで値が切り替わるのがわかるとおもいます。

手元で OTP を生成して AWS 認証してみる

注: 大体どんな感じで MFA が動いてるのか観察するためにやっているので、Web アプリ置いて生成させてこれでデバイス要らず便利〜みたいなことはやらないほうが良いと思います。

IAM で適当なユーザを作って MFA を有効にします。(実際の値は雑に消しました)

f:id:kani_b:20140706173554p:plain

ぱっと見切り替わるように見えないのですが、この画面で "Show secret key for manual configuration" をクリックすると 設定用のキーが出てきます。これを先ほどのコードで使うようにします。

f:id:kani_b:20140706173612p:plain

require 'rotp'
totp = ROTP::TOTP.new("your_mfa_key")
puts totp.now

これで6桁のワンタイムパスワードが出力されるようになったと思います。watch -n 1 ./rotp.rb とかしておくと時間経過とともに変化していくはずです。 出力されたワンタイムパスワード2つ (最初に出力されたものと次に出力されたもの) を入力するとアクティベーションが完了します。

実際にログインしようとしてみると、コード側で生成されたワンタイムパスワードが使えることが確認できます。 面白いですね。

その他

さっきも書いた通り、QR コードは鍵やその他の情報をやりとりするだけのものなので、 同じ鍵を持つデバイスを複数個作ることができます。 つまり同じ QR コードをスキャンしておけば iPhone と併用している Android とかもう使わなくなったスマートフォンなどを MFA デバイスのバックアップとして持っておくことが可能です。 その分鍵がある場所が増えることになるのでユースケースによりますが。

MFA はもはや使わない理由が特に無いので、心当たりのある人は今すぐ有効にしましょう。