不要になった AWS Organizations のメンバーアカウントを削除(閉鎖)する方法

今回は、不要になった AWS Organizations 管理下のメンバーアカウントの削除を行う方法についてお伝えします。
特にこんなケースに有用かと思います。

* 社内外向けのハンズオンイベントでメンバーアカウントを作成したが不要になった
* 部署の統廃合で一部の AWS アカウントが不要になった
* メンバーアカウント作成時に ルートアカウント用のメールアドレスの指定を誤って登録した

2020年12月頃は、AWS Organizations 管理下のメンバーアカウントを削除するには、対象のメンバーアカウントに支払情報を設定し、組織から脱退させたうえで、ルートアカウントで解約処理をしないとなりませんでした。また、メンバーアカウント作成時にメールアドレスの設定を誤っていると、ルートアカウントでログインができないので対応ができない状況でした。

様々な理由から対応ができない場合は、削除をあきらめて Service Control Policy(SCP) ですべてのサービス実行を拒否(Deny)にして、対象のメンバーアカウントを使用不可にするといった対処方法を AWS Support から伝えられていました。

そんなメンバーアカウントですが、ついに削除ができるようになりました✨✨

AWS CLI での実行は @hayao_k さんの素敵な[記事](https://qiita.com/hayao_k/items/f123e4d5f692efaca17c)があります。
本記事では、API での実行方法をご紹介いたします
API の詳細については、以下のドキュメントを合わせてご確認ください。

https://docs.aws.amazon.com/ja_jp/organizations/latest/APIReference/API_CloseAccount.html

それでは、始めましょう。

## 準備
今回は AWS CloudShell 上の Python で実行します。
念のため、 AWS SDK for Python である boto3 を更新します。

venv を使うことで既存の boto3 や依存関係を壊すことなく実行できるようになります。

```sh
$ python3 -V
Python 3.7.10

$ pip3 -V
pip 22.0.4 from /home/cloudshell-user/.local/lib/python3.7/site-packages/pip (python 3.7)

$ python3 -m venv venv
$ . venv/bin/activate

$ pip3 install -U pip
$ python -V
Python 3.7.10

$ pip -V
pip 22.0.4 from /home/cloudshell-user/venv/lib64/python3.7/site-packages/pip (python 3.7)

$ pip install boto3
```

## 実行
準備ができたら、python コマンドを実行し、以下の例のようなスクリプトで ```close_account(CloseAccount API)``` を実行していきます。

```python
import boto3
client=boto3.client('organizations')
response=client.close_account(AccountId="<削除したいメンバーアカウントのAccountId>")
print(response)

# 以下は見やすく改行しています
{
 'ResponseMetadata': {
  'RequestId': '********-****-****-****-************',
  'HTTPStatusCode': 200,
  'HTTPHeaders': {
   'x-amzn-requestid': '********-****-****-****-************',
   'content-type': 'application/x-amz-json-1.1',
   'content-length': '0',
   'date': 'Wed, 30 Mar 2022 01:40:45 GMT'
  },
  'RetryAttempts': 0
 }
}
```

特にエラーなく実行出来たら、状況を確認するために ```describe_account(DescribeAccount API)``` を実行します。

```python
response=client.describe_account(AccountId="<削除したいメンバーアカウントのAccountId>")
print(response) 
# 以下は見やすく改行しています
{
 'Account': {
  'Id': '<削除したいメンバーアカウントのAccountId>',
  'Arn': 'arn:aws:organizations::************:account/o-**********/<削除したいメンバーアカウントのAccountId>',
  'Email': '<メンバーアカウントのメールアドレス>',
  'Name': '1',
  'Status': 'SUSPENDED',
  'JoinedMethod': 'CREATED',
  'JoinedTimestamp': datetime.datetime(2020, 12, 4, 2, 8, 59, 332000, tzinfo=tzlocal())
 },
 'ResponseMetadata': {
  'RequestId': '********-****-****-****-************',
  'HTTPStatusCode': 200, 'HTTPHeaders': {
   'x-amzn-requestid': '********-****-****-****-************',
   'content-type': 'application/x-amz-json-1.1',
   'content-length': '235',
   'date': 'Wed, 30 Mar 2022 02:51:22 GMT'
  },
  'RetryAttempts': 0
 }
}
```

**Status** 要素の値を確認すると ```SUSPENDED``` になっています。
この **Status** については、実行後すぐは、 ```PENDING_CLOSURE``` (保留中の閉鎖)状態になり、進行すると前述の通りの ```SUSPENDED``` (停止)状態に遷移します。

### (おまけ)マネージメントコンソールからの実行
@hayao_k さんの記事にあるとおり、 AWS Organizations のコンソールから、削除したいアカウントの詳細を開き、画面右上にある「閉じる」ボタンから削除が可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/1f5452c0-96f8-0ac4-3d55-d958976d0127.png)


「閉じる」ボタンをクリックすると下図が表示されるので、内容を確認してチェックをし、削除対象のアカウントIDを入力後、「アカウントを閉じる」ボタンをクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/81d9be87-5dc6-bfe9-9eab-bc5d0b5b30c9.png)

## 注意したい点
30日間で、一度に削除(閉鎖)できるアカウント数は、組織内のアクティブアカウント数の 10% までとなっています。
そのため、アカウント数の全体が 100 とした場合に不要なアカウントが 20 あるとすると、多少の誤差が出る可能性がありますが、計算上は、以下のような流れで削除していくことになります。

|日数|アカウント数|削除するアカウント数|残不要アカウント数|
|---|---|---|---|
|0日|100 → **90**|**10**(100の10%)|20 → **10**|
|30日後|90 → **81**|**9**(90の10%)|10 → **1**|
|60日後|81 → **80**|**1**|1→ **0**|

　
30日間で 10% を超える数の閉鎖を試みると、以下のような表示がなされます。

マネージメントコンソールでの表示：
30日以内の制限を超えたと表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/548623/3742af8c-5a23-0772-5dbe-c7a860cbbbff.png)

API 実行時の表示：
こちらも「``You have exceeded close account quota for the past 30 days.``」と出力されていることがわかります。
```python
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/cloudshell-user/venv/lib64/python3.7/site-packages/botocore/client.py", line 401, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/home/cloudshell-user/venv/lib64/python3.7/site-packages/botocore/client.py", line 731, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.ConstraintViolationException: An error occurred (ConstraintViolationException) when calling the CloseAccount operation: You have exceeded close account quota for the past 30 days.
```


---
　
記載されている会社名、製品名、サービス名、ロゴ等は各社の商標または登録商標です。