thirose’s blog

openstackやpythonなどなど

KeystoneのTime-based One-time Password(TOTP)を設定してみた

TOTPとは、どういうログインになるのか...それを知りたく設定してみました。なお当初期待していたログインはMulti Factor Authentication(MFA)的なのを期待していましたが、挙動としては期待していたものと少し違いました。 ここで自分のやりたかったことち違ってたことに気がつけると幸せな気がします。

で、TOTPを使うとどのようなことができるのか。という話

簡潔にまとめると、Google Authenticator を使ってログインが可能になります。
secret keyを作りkeystoneとGoogle authenticatorに登録しログインすると、
ログイン時にユーザ名とgoogle authenticatorに表示されている6桁の番号を入力するとログインできるようになるという仕組みです。

実際に設定してみる

f:id:hirosetakahito:20190207190255p:plain OpenStack Docs: Time-based One-time Password (TOTP) OpenStackのドキュメントは基本的に役に立ちませんが、あるとないでは情報量の違いがあるので参照しています。

Keystoneは基本機能として、TOTPを提供しています。そのため、/etc/keystone/keystone.conf の [auth] の methods に totp を追加することになる。

[auth]
methods = external,password,token,totp

書く環境でログイン方法はいろいろあると思いますが、上記のような感じで最後にtotpを追加しています。

次にユーザ用に使うsecret keyを作成します。これは、sample同様

import base64
message = '1234567890123456'
print base64.b32encode(message).rstrip('=')

で作れます。 messageのところは、任意の文字列なので、自分で書き換えると良いです。

次はcreadentialの作成 これはサンプルがややこしく脱落する可能性があるところ。

USER_ID=YOUR_USER_ID
SECRET=YOUR_CREATED_SECRET

curl -i \
  -H "Content-Type: application/json" \
  -d '
{
    "credential": {
        "blob": "'$SECRET'",
        "type": "totp",
        "user_id": "'$USER_ID'"
    }
}' \
  http://YOUR_KEYSTONE_ENDPOINT:5000/v3/credentials ; echo

USER_IDは各自調べるのが良いでしょう。SECRETは先ほど作成したものを使います。
keystoneのendpointも自分のendpointを設定しましょう。
しかし、このまま実行すると、以下のような401 errorが返ってきます。

{"error": {"message": "The request you have made requires authentication.", "code": 401, "title": "Unauthorized"}}

なので、Content-typeの次の行に -H "X-Auth-Token: YOUR_TOKEN"\ の一行を追加する必要があります。
そして、実行すれば 201 が返ってくるので、keystone側の準備は完了です。

次にgoogle authenticatorをスマートフォンにインストールします。
インストールしている間に、登録用のQRコードを生成します。

import qrcode
user_name=YOUR_USER_ID_OR_NAME
secret='GEZDGNBVGY3TQOJQGEZDGNBVGY'
uri = 'otpauth://totp/{name}?secret={secret}&issuer={issuer}'.format(
    name=user_name,
    secret=secret,
    issuer='Keystone')

img = qrcode.make(uri)
img.save('totp.png')

google authenticatorがログインされたら、そのアプリを開き、上記で作成したQRコードを読み取りましょう。
PASS CODEが表示されます。 ここで表示されるPASS CODEは30秒に一回更新されます。

使い方

f:id:hirosetakahito:20190207190251p:plain Token発行をAPIで実現したい場合は、サンプルの最後に書かれているように、methodsをtotpにしてUSER_IDとPASS CODEでAPIを叩けばTokenが発行されます。

ちなみに、コードだと、 keystone/totp.py at d97832e8e826e37171b727072c720a9b589998dd · openstack/keystone · GitHub この部分ですが、 keystoneに登録したsecretを使い6桁のPASS CODEを生成し、それが送られてきたPASS CODEと一致してるかどうかの確認をしています。 一致していた場合は、valid_passcode フラグをTrueにして認証をおえています。

ここまできたところで、私が期待していたMFAではないことに気がつきましたが、 それはまた別にありそうなので調べることとしました。
OpenStack Docs: MFA Auth Receipt