🐈

AWS SDK for JavaScript v3はMFA認証を自動でやってくれなくなったぞ

に公開

AWS SDK for JavaScript を v2 から v3 にアップデートしたら、MFA認証が失敗するという思わぬ落とし穴に遭遇した。

ローカル開発環境で、~/.aws/credentials の設定と MFA (Multi-Factor Authentication) を使って一時クレデンシャルを取得していたのだが、v3ではMFAの対話的認証を自動でやってくれないらしい

v2ではどうだったの?

v2では AWS.SharedIniFileCredentials を使うことで、.aws/configmfa_serial が設定されていれば、自動的にMFAプロンプトが表示されて認証してくれていた。

ところが、v3はモジュールベースになったことで @aws-sdk/credential-providersfromIni() を使っても、デフォルトではMFAを要求するプロファイルに対して何の対話も行われずに失敗してしまう。……これが原因だったか。

解決策:mfaProvider を使って自前で入力プロンプトを出す

v3では fromIni()mfaProvider を渡して、自前でコード入力を処理する必要がある。

実装例:

import readline from 'readline';
import { fromIni } from "@aws-sdk/credential-providers";

export const mfaProvider = async () => {
  const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
  });

  return new Promise((resolve) => {
    rl.question(`Enter MFA code for the following account: `, (answer) => {
      rl.close();
      resolve(answer);
    });
  });
};

export const getCredentials = () => {
  return fromIni({
    profile: process.env.AWS_PROFILE, // AWS_PROFILE 環境変数を使用
    mfaProvider
  });
};

このコードはMFA認証部分をライブラリ化していて、ツール側でこれを利用して実際にMFA認証していく。

DynamoDBにアクセスするような場合は以下のようにする。

実装例:

import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
import { getCredentials } from "./credential.js";

const REGION = "ap-northeast-1";

const getAllData = async (credentials) => {
  const client = new DynamoDBClient({
    region: REGION,
    credentials
  });

  // ここでデータ取得処理を行う
};

(async () => {
  try {
    const credentials = await getCredentials();
    await getAllData(credentials);
  } catch (e) {
    console.error("Error:", e);
  }
})();

スクリプトを実行すると、CLIで

Enter MFA code for the following account:

という表示がされて一時クレデンシャルを入力できるようになる。

まとめ

  • v2ではMFAを自動で処理してくれたが、v3ではそうはいかない。

  • fromIni() に mfaProvider を指定すれば、対話的にMFAコードを入力させることが可能。。

  • ローカルでMFAが必須なプロファイルを使っている人は、v3移行時に要注意!

もう少しスムーズにMFA認証できるようにならないかな~

Discussion