【Amazon Workspaces】多要素認証で使用していたgoogle-authenticatorでQRコードの生成ができなくなっていたので、スクリプトを作成して対応した話

記事タイトルとURLをコピーする

こんにちは、エンタープライズクラウド部CR課の益田です。さて、今回は、Amazon Workspacesで多要素認証を使用していたら、使用していたツール(google-authenticator)でQRコードが生成できなくなっていたので、スクリプトを作成して対処した話になります。

現象

google-authenticatorを使用してWorkspacesを多要素認証で運用していたら、QRコードの生成ができなくなった。(2024/10現在は生成できるようになっています)
※Workspacesを多要素認証で運用する方法は以下の記事をご参考ください。

blog.serverworks.co.jp

構成図

オレンジ色の枠の部分で問題が発生

原因

当該アプリは、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

当時の対処方法

    1. ソースコードを修正し、別の外部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メール送付できる機能の実装かなと考えています。
本ブログがどなたかの助けになれば幸いです。

参考

URI string format

RFC 4226 - HOTP: An HMAC-Based One-Time Password Algorithm 日本語訳

RFC 6238 - TOTP: Time-Based One-Time Password Algorithm 日本語訳