3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

AWSの各アカウントのインスタンス一覧を取得する

Posted at

このスクリプトの目的

AWSをある程度活用していくと、組織(Organizations)を駆使して複数のAWSアカウントを使い分けることが多いと思います。そのような場合に、横断的に情報を取得するサンプルコードを書いてみました。
データ全取得はそれなりに時間がかかるので、JSONファイルにデータを書き出してから活用するのがおすすめです。AWS SDKの型情報をそのまま使っておけば、何を利用するかはあとで決めることができます。

簡単な解説

まず組織内のアカウント一覧を取得し、取得した各アカウントにAssumeRoleしながら情報を収集していきます。
今回はec2インスタンスの取得だけを行っていますが、RDS等も簡単に追加できます。

Info[]型としてデータをまとめてJSONで書き出しているので、あとはこのJSONを読み込んで煮るなり焼くなりしてください。

サンプルコード

import {Account, Accounts} from "aws-sdk/clients/organizations";
import {EC2, Organizations, STS} from "aws-sdk";
import * as fs from "fs";
import {Instance} from "aws-sdk/clients/ec2";
import {CredentialsOptions} from "aws-sdk/lib/credentials";

// 情報を取得するために利用するRole
// プログラムから、各アカウントのこのRoleにAssumeRoleできる必要がある
const AccessRole = "OrganizationAccountAccessRole"

type Info = {
    account: Account
    instances: Instance[]
}

async function assumeRole(account: Account): Promise<CredentialsOptions> {
    const sts = new STS()
    const RoleArn = `arn:aws:iam::${account.Id}:role/${AccessRole}`
    console.log(`Switch to ${RoleArn}`)
    const {Credentials} = await sts.assumeRole({
        RoleArn,
        RoleSessionName: "FetchInstances"
    }).promise()
    if (!Credentials) {
        throw new Error("Failed to switch Role")
    }
    // CredentialsOptionsと大文字小文字が違うので、ここで変換
    return {
        accessKeyId: Credentials.AccessKeyId,
        secretAccessKey: Credentials.SecretAccessKey,
        sessionToken: Credentials.SessionToken,
    }
}

async function getAccounts(org?: Organizations, NextToken?: string): Promise<Accounts> {
    console.log(`getAccount ${NextToken || "initial"}`)
    // ap-northeast-1にはOrganizationsエンドポイントが存在しない。
    if (!org) {
        org = new Organizations({
            region: "us-east-1",
            endpoint: "https://organizations.us-east-1.amazonaws.com",
        })
    }
    let result: Account[] = []
    const accounts = await org.listAccounts({
        NextToken,
    }).promise()
    if (accounts.Accounts) {
        result = result.concat(accounts.Accounts)
    }
    if (accounts.NextToken) {
        result = result.concat(await getAccounts(org, accounts.NextToken))
    }
    return result
}

async function getInstances(ec2: EC2, NextToken?: string): Promise<Instance[]> {
    console.log(`getInstances ${NextToken || "initial"}`)
    const instances = await ec2.describeInstances({
        NextToken
    }).promise()
    if (!instances.Reservations) {
        return []
    }
    let result: Instance[] = []
    for (const r of instances.Reservations) {
        if (r.Instances) {
            result = result.concat(r.Instances)
        }
    }
    if (instances.NextToken) {
        result = result.concat(await getInstances(ec2, instances.NextToken))
    }
    return result
}


(async function run() {
    // 組織内のアカウントを全部取得
    const accounts = await getAccounts()
    const result: Info[] = []
    for (const account of accounts) {
        // 個別のアカウントにAssumeRoleしながら情報を取得する
        console.log(`Processing account ${account.Id} (${account.Name})`)
        const credentials = await assumeRole(account)
        result.push({
            account,
            instances: await getInstances(new EC2({credentials})),
        })
    }
    const filepath = "./result.json"
    console.log(`Write result to ${filepath}`)
    await new Promise(r => fs.writeFile(filepath, JSON.stringify(result, null, 2), r))
})()
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?