🏢

AWS OrganizationsのチュートリアルをAWS CLIで実施してみた

に公開

チュートリアルの概要

自社のAWSアカウントは既にAWS Organizationsの組織のメンバーアカウントとなっていることもあり、今までAWS Organizationsに触れる機会はありませんでした。[1]
しかし、最近勉強しているAWS Certified DevOps Engineer - Professionalの試験範囲に含まれており、知識の定着に苦労しているため、AWS公式のチュートリアルを私用のAWSアカウントで実施してみることにしました。
https://docs.aws.amazon.com/organizations/latest/userguide/orgs_tutorials_basic.html
チュートリアルの流れは以下の通りです。

  • Step 1. 組織を作成
    • 既存のAWSアカウント①にて組織を作成
    • 既存のAWSアカウント②をメンバーアカウントとして組織に招待
    • AWSアカウント③をメンバーアカウントとして組織に新規作成
  • Step 2. OUを作成
    • ルート直下にProduction OUを作成
    • Production OU直下にMainApp OUを作成
    • AWSアカウント③をMainApp OUに所属させる
    • AWSアカウント②をProduction OUに所属させる
  • Step 3. SCPを作成
    • SCPを有効化
    • SCP①を作成
    • SCP②を作成
    • SCP③を作成
    • SCP①をルートにアタッチ
    • SCP②をProduction OUにアタッチしてFullAWSAccess SCPをデタッチ
    • SCP③をMainApp OUにアタッチ
  • Step 4. SCPをテスト
    • AWSアカウント①にて挙動を確認
    • AWSアカウント②にて挙動を確認
    • AWSアカウント③にて挙動を確認

ここで、SCPの効果を確認しやすくするために、チュートリアルで作成するSCPの内容を以下のように改変します。

SCP AWS公式 今回
Amazon CloudTrail設定変更拒否 Amazon S3バケット一覧取得拒否
Amazon EC2・ELB・AWS CodeCommit・Amazon CloudTrail・AWS CodeDeploy全操作許可 Amazon S3・Amazon SNS・AWS IAM全操作許可
Amazon DynamoDB全操作拒否 Amazon SNS全操作拒否

チュートリアル完了後の構成は以下のようになります。

ただ手順通りに実施するだけではつまらないので、今回はAWS CLIを使用します。[2]

Step 1. 組織を作成

AWS Organizationsの組織を作成し、既存のAWSアカウントを招待したり、新規のAWSアカウントを作成したりします。

既存のAWSアカウント①にて組織を作成

まず、既存のAWSアカウント①で組織を作成します。

AWSアカウント1
aws organizations create-organization --feature-set ALL --profile account1
実行結果
{
    "Organization": {
        "Id": "o-ym7cqc3anj",
        "Arn": "arn:aws:organizations::111111111111:organization/o-ym7cqc3anj",
        "FeatureSet": "ALL",
        "MasterAccountArn": "arn:aws:organizations::111111111111:account/o-ym7cqc3anj/111111111111",
        "MasterAccountId": "111111111111",
        "MasterAccountEmail": "account1@example.com",
        "AvailablePolicyTypes": [
            {
                "Type": "SERVICE_CONTROL_POLICY",
                "Status": "ENABLED"
            }
        ]
    }
}

この操作により、AWSアカウント①が組織の管理アカウントとなります。
--feature-setオプションの値はCONSOLIDATED_BILLINGまたはALLから選択します。
AWS Organizationsの一括請求(組織下のAWSアカウントの利用料金の請求を1つにまとめる機能)のみ使用したい場合はCONSOLIDATED_BILLING、今回のようにそれ以外の機能も利用したい場合はALLを指定します。[3]
AWSアカウント①のルートユーザ宛てに以下のようなメールが届くので、指示通りリンクをクリックしてメールアドレスを検証します。

既存のAWSアカウント②をメンバーアカウントとして組織に招待

組織を作成し終えたので、既存のAWSアカウント②を招待してみます。

AWSアカウント1
aws organizations invite-account-to-organization --target Id=222222222222,Type=ACCOUNT --profile account1
実行結果
{
    "Handshake": {
        "Id": "h-432e056a326a47508948e9c093149931",
        "Arn": "arn:aws:organizations::111111111111:handshake/o-ym7cqc3anj/invite/h-432e056a326a47508948e9c093149931",
        "Parties": [
            {
                "Id": "222222222222",
                "Type": "ACCOUNT"
            },
            {
                "Id": "ym7cqc3anj",
                "Type": "ORGANIZATION"
            }
        ],
        "State": "OPEN",
        "RequestedTimestamp": "2025-07-23T15:43:52.422000+09:00",
        "ExpirationTimestamp": "2025-08-07T15:43:52.422000+09:00",
        "Action": "INVITE",
        "Resources": [
            {
                "Value": "o-ym7cqc3anj",
                "Type": "ORGANIZATION",
                "Resources": [
                    {
                        "Value": "account1@example.com",
                        "Type": "MASTER_EMAIL"
                    },
                    {
                        "Value": "account1@example.com",
                        "Type": "MASTER_NAME"
                    },
                    {
                        "Value": "ALL",
                        "Type": "ORGANIZATION_FEATURE_SET"
                    }
                ]
            },
            {
                "Value": "222222222222",
                "Type": "ACCOUNT"
            }
        ]
    }
}

--targetオプションは必須ですが、AWSアカウントIDの他に以下のようにルートユーザのメールアドレスを指定することもできます。[4]

AWSアカウント1
aws organizations invite-account-to-organization --target Id=account2@example.com,Type=EMAIL --profile account1

既存のAWSアカウントを組織に招待した場合、招待された側のAWSアカウントで15日以内に承認操作を実行する必要があります。
まずはAWSアカウント②にて招待が届いていることを確認します。

AWSアカウント2
aws organizations list-handshakes-for-account --profile account2
実行結果
{
    "Handshakes": [
        {
            "Id": "h-432e056a326a47508948e9c093149931",
            "Arn": "arn:aws:organizations::111111111111:handshake/o-ym7cqc3anj/invite/h-432e056a326a47508948e9c093149931",
            "Parties": [
                {
                    "Id": "222222222222",
                    "Type": "ACCOUNT"
                },
                {
                    "Id": "ym7cqc3anj",
                    "Type": "ORGANIZATION"
                }
            ],
            "State": "OPEN",
            "RequestedTimestamp": "2025-07-23T15:43:52.422000+09:00",
            "ExpirationTimestamp": "2025-08-07T15:43:52.422000+09:00",
            "Action": "INVITE",
            "Resources": [
                {
                    "Value": "o-ym7cqc3anj",
                    "Type": "ORGANIZATION",
                    "Resources": [
                        {
                            "Value": "account1@example.com",
                            "Type": "MASTER_EMAIL"
                        },
                        {
                            "Value": "account1@example.com",
                            "Type": "MASTER_NAME"
                        },
                        {
                            "Value": "ALL",
                            "Type": "ORGANIZATION_FEATURE_SET"
                        }
                    ]
                },
                {
                    "Value": "222222222222",
                    "Type": "ACCOUNT"
                }
            ]
        }
    ]
}

そして、実行結果で確認したハンドシェイクIDを指定し、AWSアカウント②で招待を承認します。

AWSアカウント2
aws organizations accept-handshake --handshake-id h-432e056a326a47508948e9c093149931 --profile account2
実行結果
aws organizations accept-handshake --handshake-id h-432e056a326a47508948e9c093149931 --profile account2
{
    "Handshake": {
        "Id": "h-432e056a326a47508948e9c093149931",
        "Arn": "arn:aws:organizations::111111111111:handshake/o-ym7cqc3anj/invite/h-432e056a326a47508948e9c093149931",
        "Parties": [
            {
                "Id": "222222222222",
                "Type": "ACCOUNT"
            },
            {
                "Id": "ym7cqc3anj",
                "Type": "ORGANIZATION"
            }
        ],
        "State": "ACCEPTED",
        "RequestedTimestamp": "2025-07-23T15:43:52.422000+09:00",
        "ExpirationTimestamp": "2025-08-07T15:43:52.422000+09:00",
        "Action": "INVITE",
        "Resources": [
            {
                "Value": "o-ym7cqc3anj",
                "Type": "ORGANIZATION",
                "Resources": [
                    {
                        "Value": "account1@example.com",
                        "Type": "MASTER_EMAIL"
                    },
                    {
                        "Value": "account1@example.com",
                        "Type": "MASTER_NAME"
                    },
                    {
                        "Value": "ALL",
                        "Type": "ORGANIZATION_FEATURE_SET"
                    }
                ]
            },
            {
                "Value": "222222222222",
                "Type": "ACCOUNT"
            }
        ]
    }
}

これでAWSアカウント②は組織のメンバーアカウントとなりました。
今回は承認操作をAWS CLIで実行しましたが、AWSアカウント②のルートユーザのメールアドレスに届いているメール内のリンクをクリックして承認することもできます。

AWSアカウント③をメンバーアカウントとして組織に新規作成

組織内に新規のAWSアカウント③を作成します。

AWSアカウント1
aws organizations create-account --email account3@example.com --account-name "MainApp Account" --profile account1
実行結果
{
    "CreateAccountStatus": {
        "Id": "car-796301adbdee4a59bb2c0a11cd3a6fe0",
        "AccountName": "MainApp Account",
        "State": "IN_PROGRESS",
        "RequestedTimestamp": "2025-07-23T16:03:52.083000+09:00"
    }
}

これでAWSアカウント③の初期化が始まります。
しばらく経ったら、実行結果に含まれているIdフィールドの値を指定して作成進捗を確認してみましょう。

AWSアカウント1
aws organizations describe-create-account-status --create-account-request-id car-796301adbdee4a59bb2c0a11cd3a6fe0 --profile account1
実行結果
{
    "CreateAccountStatus": {
        "Id": "car-796301adbdee4a59bb2c0a11cd3a6fe0",
        "AccountName": "MainApp Account",
        "State": "SUCCEEDED",
        "RequestedTimestamp": "2025-07-23T16:03:52.151000+09:00",
        "CompletedTimestamp": "2025-07-23T16:03:54.731000+09:00",
        "AccountId": "333333333333"
    }
}

Stateフィールドの値がSUCCEEDEDになっているので、AWSアカウント③の作成もこれにて完了です。
AWS Organizationsの機能を利用してメンバーアカウントを開設すると、そのアカウント内にAWS IAMロール「OrganizationAccountAccessRole」が自動で作成されます。[5]
OrganizationAccountAccessRoleにはAWS IAMポリシー「AdministratorAccess」(全操作許可)がアタッチされており、信頼ポリシーにて組織の管理アカウントが本AWS IAMロールを引き受けられるよう設定されています。
--role-nameオプションを使用してOrganizationAccountAccessRoleに任意の名前をつける場合、組織内の全メンバーアカウントで名前を統一することが推奨されています。
また、--iam-user-access-to-billingオプションではメンバーアカウントのAWS IAMユーザ・ロールが自身の請求情報を確認できるか否か指定できます。
今回は本オプションを使用していないので、既定のALLOW扱いとなりますが、DENYを指定するとルートユーザ以外は請求情報を確認できなくなります。

Step 2. OUを作成

OU(Organizational Unitの略称で、組織内のグループ)を2つ作成し、それぞれにメンバーアカウントを所属させます。

ルート直下にProduction OUを作成

ルートの直下にOUを作成するため、まずはルートのIDを確認します。

AWSアカウント1
aws organizations list-roots --profile account1
実行結果
{
    "Roots": [
        {
            "Id": "r-8no9",
            "Arn": "arn:aws:organizations::111111111111:root/o-ym7cqc3anj/r-8no9",
            "Name": "Root",
            "PolicyTypes": []
        }
    ]
}

ルートのIDがr-8no9であると判明したため、この値を指定してルートの直下にProduction OUを作成します。

AWSアカウント1
aws organizations create-organizational-unit --parent-id r-8no9 --name Production --profile account1
実行結果
{
    "OrganizationalUnit": {
        "Id": "ou-8no9-0d4y4db2",
        "Arn": "arn:aws:organizations::111111111111:ou/o-ym7cqc3anj/ou-8no9-0d4y4db2",
        "Name": "Production"
    }
}

Production OU直下にMainApp OUを作成

続いて、Production OUの直下にMainApp OUを作成します。
--parent-idオプションの値として、先ほどの実行結果に含まれるProduction OUのIDを指定します。

AWSアカウント1
aws organizations create-organizational-unit --parent-id ou-8no9-0d4y4db2 --name MainApp --profile account1
実行結果
{
    "OrganizationalUnit": {
        "Id": "ou-8no9-k44x3nyx",
        "Arn": "arn:aws:organizations::111111111111:ou/o-ym7cqc3anj/ou-8no9-k44x3nyx",
        "Name": "MainApp"
    }
}

AWSアカウント③をMainApp OUに所属させる

OUを作成したら、メンバーアカウントをOUに所属させます。
まず、AWSアカウントID、ルートのID、MainApp OUのIDを指定し、AWSアカウント③をルートからMainApp OUに移動します。
なお、AWSアカウント3のIDはアカウント作成完了時の実行結果から分かります。

AWSアカウント1
aws organizations move-account --account-id 333333333333 --source-parent-id r-8no9 --destination-parent-id ou-8no9-k44x3nyx --profile account1
実行結果

何も表示されなければ成功です。

AWSアカウント②をProduction OUに所属させる

先ほどと同様に、AWSアカウントID、ルートのID、Production OUのIDを指定し、AWSアカウント②をルートからProduction OUに移動します。

AWSアカウント1
aws organizations move-account --account-id 222222222222 --source-parent-id r-8no9 --destination-parent-id ou-8no9-0d4y4db2 --profile account1
実行結果

さて、ここまで来たらAWSマネジメントコンソールにて組織の構造を確認してみましょう。
※画像を一部加工しています。

Step 3. SCPを作成

SCP(Service Control Policyの略称で、AWS IAMユーザ・ロールの権限の上限を制限するポリシー)を作成し、ルートやOUにアタッチしていきます。

SCPを有効化

既定では全てのポリシータイプ[6]が無効化されているため、SCPを有効化する必要があります。

AWSアカウント1
aws organizations enable-policy-type --root-id r-8no9 --policy-type SERVICE_CONTROL_POLICY --profile account1
実行結果
{
    "Root": {
        "Id": "r-8no9",
        "Arn": "arn:aws:organizations::111111111111:root/o-ym7cqc3anj/r-8no9",
        "Name": "Root",
        "PolicyTypes": []
    }
}

ちなみに、組織作成時の実行結果のAvailablePolicyTypesフィールドを見ると、あたかもSCPが有効化されているように見えます。
しかし、このフィールドは非推奨で、実際に有効化されているポリシータイプを確認するにはlist-rootsコマンドを使用します。

AWSアカウント1
aws organizations list-roots --profile account1
実行結果
{
    "Roots": [
        {
            "Id": "r-8no9",
            "Arn": "arn:aws:organizations::111111111111:root/o-ym7cqc3anj/r-8no9",
            "Name": "Root",
            "PolicyTypes": [
                {
                    "Type": "SERVICE_CONTROL_POLICY",
                    "Status": "ENABLED"
                }
            ]
        }
    ]
}

SCP①を作成

Amazon S3バケットの一覧の取得を拒否するSCP「deny-listing-s3-buckets」を作成します。
まず、SCPの内容をJSONファイルに記載します。

deny-listing-s3-buckets.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyListingS3Buckets",
            "Effect": "Deny",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "*"
        }
    ]
}

次に、上記のJSONファイルを指定してSCPを作成します。

AWSアカウント1
aws organizations create-policy --content file://C:\\Users\\example\\deny-listing-s3-buckets.json --description "Deny listing S3 buckets" --name deny-listing-s3-buckets --type SERVICE_CONTROL_POLICY --profile account1
実行結果
{
    "Policy": {
        "PolicySummary": {
            "Id": "p-z212vwzi",
            "Arn": "arn:aws:organizations::111111111111:policy/o-ym7cqc3anj/service_control_policy/p-z212vwzi",
            "Name": "deny-listing-s3-buckets",
            "Description": "Deny listing S3 buckets",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        },
        "Content": "{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"DenyListingS3Buckets\",\n            \"Effect\": \"Deny\",\n            \"Action\": \"s3:ListAllMyBuckets\",\n            \"Resource\": \"*\"\n        }\n    ]\n}"
    }
}

SCP②を作成

先ほどと同様に、

  • Amazon S3
  • Amazon SNS
  • AWS IAM

の全操作を許可するSCP「allow-s3-sns-iam-actions」を作成します。
まず、SCPの内容をJSONファイルに記載します。

allow-s3-sns-iam-actions.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowS3SNSIAMActions",
            "Effect": "Allow",
            "Action": [ 
                "s3:*",
                "sns:*",
                "iam:*"
            ],
            "Resource": "*"
        }
    ]
}

次に、上記のJSONファイルを指定してSCPを作成します。

AWSアカウント1
aws organizations create-policy --content file://C:\\Users\\example\\allow-s3-sns-iam-actions.json --description "Allow S3, SNS, and IAM actions" --name allow-s3-sns-iam-actions --type SERVICE_CONTROL_POLICY --profile account1
実行結果
{
    "Policy": {
        "PolicySummary": {
            "Id": "p-ggsoutlc",
            "Arn": "arn:aws:organizations::111111111111:policy/o-ym7cqc3anj/service_control_policy/p-ggsoutlc",
            "Name": "allow-s3-sns-iam-actions",
            "Description": "Allow S3, SNS, and IAM actions",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        },
        "Content": "{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"AllowS3SNSIAMActions\",\n            \"Effect\": \"Allow\",\n            \"Action\": [ \n                \"s3:*\",\n                \"sns:*\",\n                \"iam:*\"\n            ],\n            \"Resource\": \"*\"\n        }\n    ]\n}"
    }
}

SCP③を作成

先ほどと同様に、Amazon SNSの全操作を拒否するSCP「deny-sns-actions」を作成します。
まず、SCPの内容をJSONファイルに記載します。

deny-sns-actions.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenySNSActions",
            "Effect": "Deny",
            "Action": "sns:*",
            "Resource": "*"
        }
    ]
}

次に、上記のJSONファイルを指定してSCPを作成します。

AWSアカウント1
aws organizations create-policy --content file://C:\\Users\\example\\deny-sns-actions.json --description "Deny SNS actions" --name deny-sns-actions --type SERVICE_CONTROL_POLICY --profile account1
実行結果
{
    "Policy": {
        "PolicySummary": {
            "Id": "p-k7n9l5bl",
            "Arn": "arn:aws:organizations::111111111111:policy/o-ym7cqc3anj/service_control_policy/p-k7n9l5bl",
            "Name": "deny-sns-actions",
            "Description": "Deny SNS actions",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        },
        "Content": "{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"DenySNSActions\",\n            \"Effect\": \"Deny\",\n            \"Action\": \"sns:*\",\n            \"Resource\": \"*\"\n        }\n    ]\n}"
    }
}

SCP①をルートにアタッチ

ここからは作成したSCPをアタッチしていきます。
まず、deny-listing-s3-buckets SCPを組織のルートにアタッチします。
--policy-idはSCP作成時のレスポンスで確認できます。

AWSアカウント1
aws organizations attach-policy --policy-id p-z212vwzi --target-id r-8no9 --profile account1
実行結果

何も表示されなければ成功です。

SCP②をProduction OUにアタッチしてFullAWSAccess SCPをデタッチ

次は、allow-s3-sns-iam-actions SCPをProduction OUにアタッチします。

AWSアカウント1
aws organizations attach-policy --policy-id p-ggsoutlc --target-id ou-8no9-0d4y4db2 --profile account1
実行結果

既定でFullAWSAccess SCPがProduction OUにアタッチされていることから、この時点で本SCPは許可リストとしての意味を成しません。
そこで、FullAWSAccess SCPをProduction OUからデタッチします。
事前準備として、FullAWSAccess SCPのポリシーIDを調べます。

AWSアカウント1
aws organizations list-policies --filter SERVICE_CONTROL_POLICY --profile account1
実行結果
{
    "Policies": [
        {
            "Id": "p-FullAWSAccess",
            "Arn": "arn:aws:organizations::aws:policy/service_control_policy/p-FullAWSAccess",
            "Name": "FullAWSAccess",
            "Description": "Allows access to every operation",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": true
        },
        {
            "Id": "p-ggsoutlc",
            "Arn": "arn:aws:organizations::111111111111:policy/o-ym7cqc3anj/service_control_policy/p-ggsoutlc",
            "Name": "allow-s3-sns-iam-actions",
            "Description": "Allow S3, SNS, and IAM actions",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        },
        {
            "Id": "p-k7n9l5bl",
            "Arn": "arn:aws:organizations::111111111111:policy/o-ym7cqc3anj/service_control_policy/p-k7n9l5bl",
            "Name": "deny-sns-actions",
            "Description": "Deny SNS actions",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        },
        {
            "Id": "p-z212vwzi",
            "Arn": "arn:aws:organizations::111111111111:policy/o-ym7cqc3anj/service_control_policy/p-z212vwzi",
            "Name": "deny-listing-s3-buckets",
            "Description": "Deny listing S3 buckets",
            "Type": "SERVICE_CONTROL_POLICY",
            "AwsManaged": false
        }
    ]
}

FullAWSAccess SCPのポリシーIDがp-FullAWSAccessと分かったので、Production OUからデタッチします。

AWSアカウント1
aws organizations detach-policy --policy-id p-FullAWSAccess --target-id ou-8no9-0d4y4db2 --profile account1
実行結果

SCP③をMainApp OUにアタッチ

deny-sns-actions SCPをMainApp OUにアタッチします。

AWSアカウント1
aws organizations attach-policy --policy-id p-k7n9l5bl --target-id ou-8no9-k44x3nyx --profile account1
実行結果

Step 4. SCPをテスト

最後に、各AWSアカウントにおいてAdministratorAccessポリシーがアタッチされたAWS IAMユーザを使い、SCPの効果を確認していきましょう。

AWSアカウント①にて挙動を確認

まず、組織の管理者アカウントであるAWSアカウント①のAWS IAMユーザでAmazon S3バケットの一覧の取得を試みます。

AWSアカウント1
aws s3 ls --profile account1
実行結果

ルートにはAmazon S3バケットの一覧の取得を拒否するSCPをアタッチしていますが、管理アカウントはSCPの影響を受けないため、操作を実行することができます(今回の環境ではS3バケットを作成していないため、レスポンスは空です)。

AWSアカウント②にて挙動を確認

次に、Production OU配下のAWSアカウント②のAWS IAMユーザでAmazon S3バケットの一覧の取得を試みます。

AWSアカウント2
aws s3 ls --profile account2
実行結果
An error occurred (AccessDenied) when calling the ListBuckets operation: User: arn:aws:iam::222222222222:user/account2 is not authorized to perform: s3:ListAllMyBuckets with an explicit deny in a service control policy

Production OUにアタッチしているSCPではAmazon S3の全操作を許可していますが、ルートから継承したSCPではS3バケット一覧取得を拒否しているため、操作を実行することができません。
また、同じAWS IAMユーザでAmazon SNSトピック・AWS IAMグループの一覧を取得してみます。

AWSアカウント2
aws sns list-topics --profile account2
実行結果
{
    "Topics": []
}
AWSアカウント2
aws iam list-groups --profile account2
実行結果
{
    "Groups": []
}

これらは継承したSCPやAWSアカウント②にアタッチされたFullAWSAccess SCPで明示的に許可されており、他のSCPで拒否もされていないため、操作を実行することができます(今回の環境ではAmazon SNSトピック・AWS IAMグループを作成していないため、レスポンスは空です)。

AWSアカウント③にて挙動を確認

最後に、MainApp OU配下のAWSアカウント③のAWS IAMユーザ[7]でAmazon SNSトピックの一覧の取得を試みます。

AWSアカウント3
aws sns list-topics --profile account3
実行結果
An error occurred (AuthorizationError) when calling the ListTopics operation: User: arn:aws:iam::333333333333:user/account3 is not authorized to perform: SNS:ListTopics on resource: arn:aws:sns:ap-northeast-1:333333333333:* with an explicit deny in a service control policy

MainApp OUにアタッチしたAmazon SNS全操作拒否のSCPによって、操作を実行することができません。
また、同じAWS IAMユーザでAWS IAMグループの一覧を取得してみます。

AWSアカウント3
aws iam list-groups --profile account3
実行結果
{
    "Groups": []
}

こちらは各OUとAWSアカウント3にアタッチされているSCPで明示的に許可されており、その他SCPで拒否されていないため、操作を実行することができます。
これにてチュートリアルは終了です。

環境の復元

チュートリアル開始前の環境に戻します。
組織を削除するためには、全てのメンバーアカウントを脱退または閉鎖する必要があります。
まず、招待したAWSアカウント②を組織から脱退させましょう。[8]

AWSアカウント1
aws organizations remove-account-from-organization --account-id 222222222222 --profile account1
実行結果

何も表示されなければ成功です。
次に、作成したAWSアカウント③は閉鎖しましょう。

AWSアカウント1
aws organizations close-account --account-id 333333333333 --profile account1
実行結果

AWSアカウントの完全な閉鎖には最大90日間かかります。
90日後に組織内のメンバーアカウントの一覧を確認してみます。[9]

AWSアカウント1
aws organizations list-accounts --profile account1
実行結果
{
    "Accounts": [
        {
            "Id": "111111111111",
            "Arn": "arn:aws:organizations::111111111111:account/o-ym7cqc3anj/111111111111",
            "Email": "account1@example.com",
            "Name": "account1@example.com",
            "Status": "ACTIVE",
            "JoinedMethod": "INVITED",
            "JoinedTimestamp": "2025-07-23T12:26:54.864000+09:00"
        }
    ]
}

組織内にメンバーアカウントがいないことを確認できたら組織を削除します。

AWSアカウント1
aws organizations delete-organization --profile account1
実行結果

脚注
  1. メンバーアカウントは管理アカウントから権限を委任されない限り、AWS Organizationsの機能で遊ぶことができません。 ↩︎

  2. AWSマネジメントコンソール上で操作すると、スクリーンショットを撮らなければならず、とても面倒という事情もあります…。 ↩︎

  3. --feature-setオプションを使用しない場合はALL扱いとなり、AWS Organizationsの全機能が有効化されます。 ↩︎

  4. AWS CLIのリファレンスを見ると、TypeとしてORGANIZATIONを指定できそうですが、実際には指定するとエラーが出ます。将来、組織ごと招待できる日が来るのでしょうか…? ↩︎

  5. 組織に招待されたAWSアカウントの場合、OrganizationAccountAccessRoleは自動で作成されません。 ↩︎

  6. 現在AWS Organizationsで使用可能なポリシーは8種類(SCP、RCP、宣言型ポリシー、バックアップポリシー、タグポリシー、チャットボットポリシー、AIサービスオプトアウトポリシー、Security Hubポリシー)あります。 ↩︎

  7. ルートユーザのパスワードを設定していないため、パスワードを再発行してからルートユーザでログインします。そして、AdministratorAccessポリシーをアタッチしたAWS IAMユーザを作成します。代わりに、AWSアカウント①のAWS IAMユーザでAWSアカウント③のOrganizationAccountAccessRoleを引き受けるという手段もあります。 ↩︎

  8. 今回はAWSアカウント②においてOrganizationAccountAccessRoleを作成していませんが、管理アカウントが引き受けられるロールであるため、作成した場合は組織脱退時に忘れずに削除しましょう。 ↩︎

  9. 本記事執筆時点で90日間経過していないため、想定される実行結果を記載しています。 ↩︎

Discussion