📝

Node.js でマルチアカウントの AWS リソース情報をファイル出力してみた

2022/05/11に公開

使用している AWS リソース情報を一覧で確認したいことってありますよね。
単一アカウントであれば、以下の方法があります。

https://dev.classmethod.jp/articles/tag-editor-seach-allregion/

https://dev.classmethod.jp/articles/cli-resource-search/

今回は、上記の方法のうち 2 つ目の記事を参考に、マルチアカウントの AWS リソース情報を json ファイルとして出力する Node.js プログラムを作成してみました。

前提

・AWS マルチアカウント構成である
・各アカウントにはスイッチロールすることができる
・スイッチロールの権限は AdministratorAccess
AWS CLI でスイッチロールができる状態である
・CLI からの呼び出しで MFA は使用していない

なお、今回はマルチリージョンでの出力は行っていませんのでご注意ください。

コード

Node.js でのスイッチロールは以下の記事のコードを流用しています。
https://zenn.dev/mn87/articles/623f9ebe0435b8

sample.js
const fs = require("fs");
const AWS = require("aws-sdk");
AWS.config.update({ region: "ap-northeast-1" });
AWS.config.apiVersions = {
  sts: "2011-06-15",
  resourcegroupstaggingapi: "2017-01-26",
};
const sts = new AWS.STS();

const main = async () => {
  const ops = {
    flag: "a",
  };
  const profiles = ["profile-name-1 ", "profile-name-2"];
  const roles = [
    "アカウント A の スイッチ用 IAM ロール ARN",
    "アカウント B の スイッチ用 IAM ロール ARN",
  ];
  const roleSessionNames = ["test1", "test2"];

  for (let i = 0; i < profiles.length; i++) {
    const credentials = new AWS.SharedIniFileCredentials({
      profile: profiles[i],
    });
    AWS.config.credentials = credentials;

    try {
      const credentials = await assumeRole(roles[i], roleSessionNames[i]);
      const options = {
        accessKeyId: credentials.AccessKeyId,
        secretAccessKey: credentials.SecretAccessKey,
        sessionToken: credentials.SessionToken,
      };
      const resourcegroupstaggingapi = new AWS.ResourceGroupsTaggingAPI(
        options
      );
      const result = await resourcegroupstaggingapi.getResources().promise();
      const str = JSON.stringify(result);

      fs.writeFile("resources.json", str, ops, (err) => {
        if (err) {
          console.log(err);
        }
      });
    } catch (error) {
      console.log(error);
    }
  }
};
main();

async function assumeRole(RoleArn, RoleSessionName) {
  const params = {
    RoleArn,
    RoleSessionName,
  };

  try {
    const result = await sts.assumeRole(params).promise();
    return result.Credentials;
  } catch (error) {
    console.log(error);
  }
}

コード内容

Node.js でのスイッチロール部分に関しては、先述の記事で説明しているので割愛します。

GetResources API

今回はリソース情報を取得するために、GetResources という API を使用しています。

https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/ResourceGroupsTaggingAPI.html#getResources-property

GetResourcesResourceGroupsTaggingAPI というサービス API に含まれるので、以下の部分で STS とともに API バージョンを指定しています。

AWS.config.apiVersions = {
  sts: "2011-06-15",
  resourcegroupstaggingapi: "2017-01-26",
};

設定値のロード

以下の部分で config ファイルに記載されているスイッチロール用の各種 profile 情報をロードします。
(ロードではなくハードコーディングですが…)

const profiles = ["profile-name-1 ", "profile-name-2"];
const roles = [
"アカウント A の スイッチ用 IAM ロール ARN",
"アカウント B の スイッチ用 IAM ロール ARN",
];
const roleSessionNames = ["test1", "test2"];

本来はハードコーディングせずに config ファイルから直接ロードしたかったのですが、ロード方法がわからなかったので、ハードコーディングになりました。
config ファイルからロードする方法があればそちらの方が良いと思います。

ループでスイッチロール

各アカウントへのスイッチロール用の profile 分ループさせて、スイッチロールごとに GetResources を呼び出しています。
取得した結果を文字列に変換してから、ファイルに追記モードで書き込んでいます。

for (let i = 0; i < profiles.length; i++) {
    const credentials = new AWS.SharedIniFileCredentials({
      profile: profiles[i],
    });
    AWS.config.credentials = credentials;

    try {
      const credentials = await assumeRole(roles[i], roleSessionNames[i]);
      const options = {
        accessKeyId: credentials.AccessKeyId,
        secretAccessKey: credentials.SecretAccessKey,
        sessionToken: credentials.SessionToken,
      };
      const resourcegroupstaggingapi = new AWS.ResourceGroupsTaggingAPI(
        options
      );
      const result = await resourcegroupstaggingapi.getResources().promise();
      const str = JSON.stringify(result);

      fs.writeFile("resources.json", str, ops, (err) => {
        if (err) {
          console.log(err);
        }
      });
    } catch (error) {
      console.log(error);
    }
  }

追記モードに関しては、ループの中で毎回指定する必要はなかったので、処理の冒頭で以下のように指定しています。

const ops = {
    flag: "a",
  };

実行方法

aws-sdk をインストールする必要があるので、以下のコマンドを実行します。

npm i aws-sdk

aws-sdk をインストール後、以下のコマンドでプログラムを実行します。

node sample.js

実行後に resources.json というファイルが生成され、各アカウントの東京リージョンのリソース情報が記載されているはずです。

整形

プログラム実行語に生成された json ファイルは不正な形式なので、フォーマットがうまくいかないと思います。
そのため、アカウントごとの切れ目を見つけて、別々の json ファイルにする必要があるのですが、切れ目の見つけ方は簡単です。

文字列検索で、PaginationToken という単語がヒットするので、この直前の { がアカウントの切れ目です。
なので、PaginationToken 直前の { から始まる 1 ブロックごとに別々の json ファイルに分けると、うまく整形できるはずです。

そもそもプログラム側で書き込む時に、 1 つの json ファイルではなく、別々の json ファイルに分けるという方法もあると思いますので、適宜変更して下さい。

その他

マルチリージョンのリソース情報を取得する場合は、リージョン分ループかつアカウント分ループの 2 重ループでできるのではないかと思っています。
そのうち試してみようと思います。

また、シェルスクリプトでもできる気はしますが、僕はスクリプトよくわからないマンなので、きっと誰かが作ってくれるのではないかと願っています。

まとめ

今回はマルチアカウントの AWS リソース情報を json ファイルとして出力する Node.js プログラムを作成してみました。
改良の余地はありますが、参考になれば幸いです。

Discussion