AWS Organizations の既存組織からメンバーアカウントを離脱してスタンドアロン化する処理を自動化してみた

AWS Organizations の API を利用して、既存組織からメンバーアカウントを組織離脱(スタンドアロン化)する処理を自動化する方法についてご紹介します。
2022.12.12

はじめに

こんにちは、筧( @TakaakiKakei )です。

最近は、AWS Organizations 間の AWS アカウント移動の自動化に取り組んでいます。 先日は AWS Organizations の API を利用して、新しい組織から別組織のメンバーアカウントに招待を送る処理を自動化しました。

今回は、既存組織からメンバーアカウントを組織離脱(スタンドアロン化)する処理の自動化に取り組んだので、その内容についてご紹介します。

前提

AWS Organizations 間の AWS アカウント移動にはいくつかステップがあります。 下記に主なステップを列挙します。

  1. 移動に伴うリソースや請求に関する検討事項を確認する
  2. 既存組織からメンバーアカウントを削除するための条件を満たす。
  3. 新しい組織からメンバーアカウントに招待を送信する。
  4. 既存組織からメンバーアカウントを削除します。
  5. メンバーアカウントで新しい組織への招待を受け入れます。

上記に加えて、AWS Control Tower の利用有無に応じた処理や、利用 API の制限についても検討が必要でしょう。

AWSアカウントのOU移動はOrganizationsでも可能ですが、Control Towerへの登録が失敗となるためService Catalogから実施する必要があります。

今回は冒頭の記載通り、4の組織離脱処理の自動化についてご紹介します。

コードの紹介

実装したコードを汎用的にしたものを紹介します。

src/handlers/organizations.py

from aws_lambda_powertools import Logger
from mypy_boto3_organizations import OrganizationsClient

logger = Logger(child=True)


class OrganizationsService:
    def __init__(self, client: OrganizationsClient):
        self._client = client

    def remove_account(self, target_accountid: str) -> None:
        # refs: https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/organizations.html#Organizations.Client.remove_account_from_organization
        self._client.remove_account_from_organization(AccountId=target_accountid)
        return
  • remove_account_from_organization メソッドを利用しています。
  • 成功した場合のレポスンスは None です。
  • 以下の内容は本筋ではないので無視いただいて結構です。
    • aws_lambda_powertools 関連
    • mypy_boto3_organizations 関連

実行例

import boto3

from src.services.organizations import OrganizationsService

# 新しい組織の管理アカウント上で Client オブジェクト生成
org_client = boto3.client(
    "organizations",
    aws_access_key_id="YOUR_ACCESS_KEY",
    aws_secret_access_key="YOUR_SECRET_KEY",
    aws_session_token="YOUR_SESSION_TOKEN",
)

org_service = OrganizationsService(client=org_client)
target_accountid = "123456789012"  # 組織離脱対象の AWS アカウント
handshake_id = org_service.remove_account(target_accountid)

上記コードは実行例です。こちらもブログ用にアレンジしています。 Client オブジェクト生成するためのクレデンシャル情報は、SecretManager などから参照しましょう。 target_accountid は、event から渡すのが良さそうですね。

tests/unit/services/test_organizations.py

from unittest.mock import MagicMock

from src.services.organizations import OrganizationsService

FIXUTRE_ACCOUNT_ID = "123456789012"


class OrganizationsService:
    def test_remove_account(self):
        # setup
        mock_client = MagicMock()
        mock_client.remove_account.return_value = None
        sut = OrganizationsService(client=mock_client)

        # exercise
        resp = sut.remove_account(FIXUTRE_ACCOUNT_ID)

        # verify
        assert resp is None
        mock_client.remove_account_from_organization.assert_called_once_with(
            AccountId=FIXUTRE_ACCOUNT_ID
        )

ユニットテストコードも紹介しておきます。 本テストの目的は導線テストになります。

おわりに

最後まで読んでいただきありがとうございます。

簡単な処理でしたが、どなたかの役に立てばと書いてみました。 参考になれば幸いです。

それではまた!