Help us understand the problem. What is going on with this article?

CLI で Authy と共通の MFA Token を生成する

More than 3 years have passed since last update.

AWS や Google 等で利用可能な MFA の仮想デバイスとしては、複数デバイス間の同期や Chrome Extension を擁する Authy が便利なわけですが、PC 特に CLI を使ってるといちいちデバイス or Chrome Extension を開く必要があり、かなり面倒です。
CLI から token を生成する OATH Toolkit の oathtool を使えば、この面倒さが少しは解消され、スクリプト化による自動処理も可能になります。
ただし、oathtool 自体は毎回 SecretKey が必要になるため、mfacodegen という名の wrapper script を用意して便利に利用できるようにします。

利用イメージは以下の通り。

mfacodegen.png

Authy Chrome Extension から SecretKey を取得する

MFA では

  • TOTP (Time-based One Time Password) RFC 6238
  • HOTP (HMAC-based One Time Password) RFC 4226

が使われていますが、これらの token を生成するには SecretKey が必要となります。

SecretKey は MFA 設定時の QR code 内に仕込まれているのですが、既に Authy を設定済の場合は アプリ上から SecretKey を見ることが出来ません。
ただし Authy は定期的に token を生成するために内部的には当然 SecretKey を保持しています。
Authy Chrome Extension は JS で token を生成しているため、Developer Tools で内部を覗けばバッチリ取得できます。

まず、Authy Chrome Extension を開き、ログインした後のアカウント一覧画面で右クリック、Inspect(検証)を開きます。

Authy.png

Developer Tools が開いたら、Console タブを開き、以下のコードを入力して実行します。

requirejs(['models/apps/app_manager'], AppManager => AppManager.get().model.forEach(app => console.log([app.accountType, app.name, app.decryptedSeed].join('\t'))))

すると、Authy の アカウントタイプ(アイコン)、名称、SecretKey が Console に出力されるはずです。

Developer_Tools.png

得られた SecretKey は、パスワード管理アプリ等を用いて安全に保管しておきましょう。

oathtool で MFA Token を生成してみる

Mac であれば、brew を使えば簡単にインストールできます。

brew install oath-toolkit

以下のコマンドで token が生成できることを確認します。

stty -echo; echo -n 'Enter SecretKey: '; read skey; echo; stty echo; oathtool -b --totp $skey

oathtool -b --totp [SecretKey] だけでも確認できますが、その場合は shell の history に SecretKey が残ってしまうので、後で .bash_history や .zsh_history から削除する必要があります。

wrapper script (mfacodegen) を作成する

このままだと SecretKey の扱いが面倒で非常に使いにくいので、

  • Service ID、SecretKey を書いた key list を用意する
  • key list は openssl で encrypt しておく
  • wrapper script が key list を参照、decrypt
  • wrapper script の引数で渡された Service ID のエントリを元に oathtool で token 生成

のような処理を行います。

暗号化した SecretKey リストファイルを作成する

一行が [ServiceID]\t[SecretKey] となるようなリスト mfalist.txt を適当な場所に生成します。

ServiceID は CLI のオプションとして無難な文字列にしておいてください。

mfalist.png

S/MIME 用の秘密鍵と証明書を生成します。

openssl req -x509 -days 3650 -newkey rsa:2048 -keyout /path/to/mfa.key -out /path/to/mfa.crt -subj '/'

作成した証明書を用いて、openssl コマンドで encrypt します。

openssl smime -encrypt -aes256 -in /path/to/mfalist.txt -out /path/to/mfalist.dat -binary -outform PEM /path/to/mfa.crt

念のため、decrypt 可能かどうか、確認しておきましょう。
以下のコマンドで、標準出力に decrypt 結果が表示されれば成功です。

openssl smime -decrypt -in /path/to/mfalist.dat -inkey /path/to/mfa.key -binary -inform PEM

元の /path/to/mfalist.txt は不要なので削除しておきます。

mfacodegen を設置する

以下のファイルを path の通った適当な場所に設置します。

最初の LIST_PATH および KEY_PATH は適宜修正してください。
また、chmod +x を忘れずに。

mfacodegen
#!/bin/bash
set -e

LIST_PATH=/path/to/mfalist.dat
KEY_PATH=~/path/to/mfa.key

usage() {
  echo "Usage: $0 [-clh] [-s service]" 1>&2
  exit 1
}

while getopts cls:h OPT; do
  case $OPT in
    c)  mode='copy'
        ;;
    l)  cmd='show'
        ;;
    s)  cmd='generate'
        service=$OPTARG
        ;;
    h)  usage
        ;;
    \?) usage
        ;;
  esac
done

[ -z "$cmd" ] && usage

generateToken() {
  list=$(loadList)
  seckey=$(echo "${list}" | awk "\$1==\"${service}\"{print \$2}")
  [ -z "$seckey" ] && { echo "Service ${service} not found." >&2; exit 1; }
  if [ "$(uname)" = 'Darwin' -a "$mode" = 'copy' ]; then
    echo -n $(oathtool -b --totp $seckey) | pbcopy
  else
    oathtool -b --totp $seckey
  fi
}

loadList() {
  if [ -p /dev/stdin ]; then
    stdin=$(cat -)
    openssl smime -decrypt -inkey $KEY_PATH -in $LIST_PATH -binary -inform PEM -passin "pass:$stdin"
  else
    openssl smime -decrypt -inkey $KEY_PATH -in $LIST_PATH -binary -inform PEM
  fi
}

showServiceList() {
  list=$(loadList)
  echo "${list}" | cut -f1 | sort
}

case "$cmd" in
  'show' )
    showServiceList
    ;;
  'generate' )
    generateToken
    ;;
esac

動作確認

-l オプションで、サービスの一覧が表示されます。

mfacodegen -l

-s [ServiceID] オプションで、指定のサービス ID の token を生成します。

mfacodegen -s github

Mac の場合は、-c -s [ServiceID] で token がクリップボードにコピーされます。

mfacodegen -c -s github

これで、CLI で MFA token が取得できるようになりました。

11/21 追記
他ツールとの連携のため、STDIN からの pass phrase 入力に対応。

02/21 修正
rsautl だと大きなファイルを encrypt できないため、smime に変更。

u-minor
sprocket
"Sprocket(スプロケット)は、Webサイトにおけるコンバージョン(購入・入会・資料請求・問合せ等)を増やしたい企業様向けに、自社開発のWeb接客ツールの導入及びコンバージョン改善コンサルティングを行っている会社です。 "
https://www.sprocket.bz/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした