こんにちは、エンタープライズクラウド部CR課の益田です。さて、今回は、Amazon Workspacesで多要素認証を使用していたら、使用していたツール(google-authenticator)でQRコードが生成できなくなっていたので、スクリプトを作成して対処した話になります。
現象
google-authenticatorを使用してWorkspacesを多要素認証で運用していたら、QRコードの生成ができなくなった。(2024/10現在は生成できるようになっています)
※Workspacesを多要素認証で運用する方法は以下の記事をご参考ください。
構成図
オレンジ色の枠の部分で問題が発生
原因
当該アプリは、Google Chart APIというQRコード生成用のAPIを使用して、QRコードの生成をしていたが、2024年3月末ごろに突然当該APIが廃止され、使用できなくなりました。
そのため、QRコードの生成をしようとすると「404 Not Found」エラーになり、QRコードが生成されない状態になっていました。
※2024年10月現在では、google-authenticatorのソースコードが修正され、APIを使用しない手法になっているため、問題なくQRコードの生成ができます。
GitHub - google/google-authenticator-libpam
当時の対処方法
- ソースコードを修正し、別の外部APIを利用またはAPIなしでQRコードを生成できるようにする。
2.QRコードを生成するアプリケーションを別にインストールし、google-authenticatorとうまく組み合わせたスクリプトを作成してQRコードを生成する。
今回はセキュリティ担保と工数の関係から「2」の手法で対応しました。
対応の流れ
仕組みの理解
google-authenticatorを実行するとSecretが生成され、それを「otpauth://totp/~」というURIに格納していたため、otpauthに関して調査しました。
otpauthのURIは以下のような要素でできていることが分かりました。 otpauth://TYPE/LABEL?PARAMETERS
要素名 | 値 | 説明 | 必須 |
---|---|---|---|
TYPE | hotp, totp |
認証情報を生成するカウンターのタイプ。 認証情報の生成には、HOTP (HMAC-Based One-Time Password)という仕組みを使用する。そして、HMACハッシュ値は「鍵」と「カウンター」と呼ばれる要素から生成する。その際に使用するカウンターをどのような要素を使用するかの選択。 hotpは初期値が決め、試行するごとにインクリメントしていく。 totpはunixtimeからステップ数を割りだして、それをカウンターとして使用する仕組み。 |
〇 |
LABEL | Issuer | アカウントが関連付けられているプロパイダーやサービス名を示す文字列。 | |
Account Name | ユーザ名やユーザのメールアドレスを示す文字列。 | 〇 | |
PARAMETERS | secrets | ワンタイム パスワードを生成するために必要な文字列。 google-authenticatorが払い出すので、その値を埋め込む。 |
〇 |
issuer | アカウントが関連付けられているプロパイダーやサービス名を示す文字列。 | 〇 | |
algorithm | 認証情報の生成に使用するハッシュアルゴリズム。SHA1,SHA256,SHA512のいずれかから選択する。デフォルトは、SHA1。 | ||
digits | ワンタイムパスワード (OTP) の桁数。6,7,8のいずれかから選択する。デフォルトは、6。 | ||
counter | TYPEが 「hotp」 の場合にのみ使用。カウンターの初期値を設定する。0,1のどちらかが良く使用される。 | 〇 (hotpの時のみ) |
|
period | TYPEが 「totp」 の場合にのみ使用。TOTP コードの有効期間を秒単位で設定する。15,30,60のいずれかから選択する。デフォルトは、30。 |
※Labelは記載した内容がアプリケーションの上の部分に表示されることになります。Issuer及びAccount Nameの両方を設定する場合は「Issuer:Account Name」とします。Labelの値の文字列には「:(コロン)」は使用できません。
例)TYPEが「hotp」の場合
# 要素を入れた例 otpauth://{TYPE}/{Issuer}:{Account Name}?secret={secretの値}&issuer={issuerの値}&algorithm={algorithmの値}&digits={digitsの値}&counter={counterの値} # 具体的な値を入れた例 otpauth://totp/workspaces:user@example.co.jp?secret=ZJXOHMOMC3IAFCEKAJZJCND3OP&issuer=workspaces&algorithm=SHA1&digits=6&counter=0
例)TYPEが「totp」の場合
# 要素を入れた例 otpauth://{TYPE}/{Issuer}:{Account Name}?secret={secretの値}&issuer={issuerの値}&algorithm={algorithmの値}&digits={digitsの値}&period={periodの値} # 具体的な値を入れた例 otpauth://totp/workspaces:user@example.co.jp?secret=ZJXOHMOMC3IAFCEKAJZJCND3OP&issuer=workspaces&algorithm=SHA1&digits=6&period=30
※Secretの値は26桁のサンプルを入れております。実際に使用される際には、google-authenticator等で作成した値を入れてください。
スクリプトの作成
以下のようなスクリプトを作成しました。
#!/bin/bash # Variable SERVICE_NAME="Workspaces" EMAIL_DOMAIN_NAME="example.co.jp" CREATE_PNG="Yes" # Function generate_qrcode () { ## ユーザが存在するかの確認 cut -d ':' -f 1 /etc/passwd |grep -x "$1" > /dev/null 2>&1 if [ $? -ne 0 ]; then echo -e "\033[31m Error: $1 User Not Found. Please check user name and run again. \033[m" exit 1 fi ## QRコード生成用のパッケージがインストールされているか確認 rpm -qa | grep qrencode |grep -v "qrencode-lib" > /dev/null 2>&1 if [ $? -ne 0 ]; then echo -e "\033[31m Error: The qrencode package is not installed. Please install the qrencode package and run this script again. \033[m" exit 1 fi ## google authenticatorのファイル生成 sudo -u $1 /usr/bin/google-authenticator -t -d -f -w 17 -r 3 -R 30 -q ## QRコードの作成 SECRET=`head -n 1 /home/$1/.google_authenticator` OTPLINK="otpauth://totp/${SERVICE_NAME}:$1@${EMAIL_DOMAIN_NAME}?secret=${SECRET}&issuer=${SERVICE_NAME}" if [ ${CREATE_PNG,,} = "yes" ]; then echo -e "\033[36m Generate QRcode and google_authenticator_qrcode_$1.png \033[m" qrencode -o google_authenticator_qrcode_$1.png ${OTPLINK} qrencode -t ansi -m 2 ${OTPLINK} return 0 else echo -e "\033[36m Generate QRcode. \033[m" qrencode -t ansi -m 2 ${OTPLINK} return 0 fi } ## 外部ファイルを読み込んで、記載されているユーザのQRコードを作成する generate_qrcode_read_file () { ## ファイルが存在するか確認 ls $1 > /dev/null if [ $? -ne 0 ]; then echo -e "\033[31m Error: $1 File Not Found. Please check filepath and run again. \033[m" exit 1 fi ## ファイルを読み込み、記載されているユーザのQRコードを作成 echo -e "\033[36m Read $1 \n \033[m" while read LINE do USERNAME=${LINE} echo -e "USERNAME:$USERNAME \n" generate_qrcode ${USERNAME} echo -e "SECRET:$SECRET \n" echo -e "----------------------------------------------------------------------------------- " done < $1 } ## 使い方 usage () { echo -e " This script generates a QRcode for GoogleAuthenticator \n\n" echo -e "\033[33m $0 -u [USERNAME] - - - Genarate QRcode for one user. \n \033[m" echo -e "\033[33m $0 -f [FILEPATH] - - - Genarate QRcode for multiple users on file. \n\033[m" exit 0 } # Main if [ "${1,,}" = "-u" -o "${1,,}" = "--user" ]; then ## 個別にユーザを指定してQRコード生成 USERNAME=$2 generate_qrcode ${USERNAME} echo "SECRET:$SECRET" exit 0 elif [ "${1,,}" = "-f" -o "${1,,}" = "--file" ]; then ## ファイルに記載されているユーザのQRコードを一括作成 FILEPATH=$2 generate_qrcode_read_file ${FILEPATH} exit 0 elif [ "${1,,}" = "-h" -o "${1,,}" = "--help" ]; then usage else echo -e "\033[31m Error: $0: invalid option \033[m" echo " Try '$0 --help' for more information." exit 1 fi
使い方
前提要件
- スクリプト実行ユーザはroot(google-authenticatorの仕様上、ユーザのホームディレクトリにファイルを作成するため)
- 以下のパッケージをインストール済み
- google-authenticator
- qrencode
- qrencode-libs
- google-authenticatorで認証に使用したいユーザは作成していること
※rootユーザで作業をお願いします。
1.任意のディレクトリに以下のファイルを配置
- generate_qrcode.sh(上記のスクリプトの内容をコピーして作成してください)
この際に変数部分(#Variable)の修正もお願いします。
変数名 | 値 | 説明 |
---|---|---|
SERVICE_NAME | Workspaces | アカウントが関連付けられているプロパイダーやサービス名を示す文字列。 今回はWorkspcesで使用するため、「Workspaces」と入力します。 |
EMAIL_DOMAIN_NAME | メールアドレスのドメイン名 | アカウント名としてメールアドレスを使用するため、メールアドレスに使用しているドメインを入力してください。 |
CREATE_PNG | Yes, No |
QRコードをPNGファイルとして生成するか否かの変数。 |
2.以下のコマンドを実行し、実行権限を付与
# chmod 744 generate_qrcode.sh
3.以下のコマンドを実行してQRコードを生成する
単一ユーザ用のQRコードを生成したい場合
# ./generate_qrcode.sh -u {USER名}
実行結果
複数ユーザ用のQRコードを一括生成したい場合
1.ユーザ名を記載したファイルを作成
改行区切りで、1行目からユーザ名を記載
以下のコマンド等でファイルを作成する
# cat <<EOF >> user.txt {USER1} {USER2} {USER3} ・ ・ ・ ・ {USER} EOF
2.以下のコマンドを実行
# ./generate_qrcode.sh -f user.txt
4.スマホアプリ等で表示されたQRコードを読み取り
- おすすめの多要素認証アプリ
- Authy
- Google Authenticator
アプリで読み取り後のイメージ
おわりに
QRコードをpngファイルで出力できるようにしたので、今後拡張するとしたらAmazon SES等を使用して、対象者へ自動でEメール送付できる機能の実装かなと考えています。
本ブログがどなたかの助けになれば幸いです。
参考
RFC 4226 - HOTP: An HMAC-Based One-Time Password Algorithm 日本語訳
RFC 6238 - TOTP: Time-Based One-Time Password Algorithm 日本語訳