1
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?

【Bash】シェルスクリプトで多数のIAMユーザーを一括削除

Posted at

はじめに

AWS環境の運用業務では、IAMユーザーの管理を行います。
部署異動や退職などにより、使われていないIAMユーザーが増えることは割とよくあることだと思います。
そのため、定期的なIAMユーザーの棚卸は、セキュリティを維持し、リソースを最適化するために欠かせません。

少数のユーザーであればコンソール上で手動削除することも可能ですが、数十のユーザーがいる場合は手間がかかるだけでなく、誤って重要なユーザーを削除してしまうリスクがあります。

こうした課題を解決する手段として、AWS CLIとシェルスクリプトを使用した複数ユーザーの一括削除が有効です。
シェルスクリプトを使用することで、手動実行に比べて以下のメリットがあります。
 作業時間を短縮
 他の作業と並行して実行
  シェルスクリプトを流しながら、他の作業を進めることができる
 人為的なミスを防ぐ
  処理をコードで自動化することで冪等性を担保(100回やっても同じ結果になる)

このように、シェルスクリプトの実行により、不要なIAMユーザーを効率的かつ正確に削除できます。

また、AWSには、マネジメントコンソール上でシェルを実行できるCloudShellというサービスがあります。
このサービスを利用することで、追加の環境設定やツールのインストールが不要であり、シェルスクリプトの実行が容易になります。

この記事では、CloudShellとシェルスクリプトを活用して、複数のIAMユーザーを効率的に削除する方法を紹介します。

方法

シェルスクリプトの処理の流れ

シェルスクリプトを使用してIAMユーザーを削除する場合、削除の前に、ユーザーに関連する以下の処理を実施する必要があります。
 ログインプロファイルの削除
 署名用証明書の削除
 Git認証情報の削除
 SSHキーの削除
 ユーザーにアタッチされたマネージドポリシーのデタッチ
 ユーザーにアタッチされたインラインポリシーの削除
 グループからユーザーを除外
 アクセスキーの削除
 MFAデバイスの削除

これらの手順を理解して、シェルスクリプトを適切に作成して実行することで、複数のIAMユーザーを効率的に削除することができます。
この点を踏まえて、シェルスクリプトによる、IAMユーザー一括削除の流れを以下のようにしました。
 1. 削除ユーザー名が記載されたテキストファイルを1行ずつ読み込み
  1-1. テキストから取得したユーザー名をもとに、IAMユーザーが存在するか確認
   1-1-1. IAMユーザーが存在する場合、以下の処理を実行
    1-1-1-1. 署名用証明書の削除
    1-1-1-2. Git認証情報の削除
    1-1-1-3. SSHキーの削除
    1-1-1-4. ユーザーに直接アタッチされているマネージドポリシーをデタッチ
    1-1-1-5. ユーザーに直接アタッチしたインラインポリシーを削除
    1-1-1-6. グループからユーザーを除外
    1-1-1-7. アクセスキー削除
    1-1-1-8. MFAデバイス削除
    1-1-1-9. ログインプロファイル削除
    1-1-1-10. 上記処理を実施後、ユーザーを削除
   1-1-2. IAMユーザーが存在しない場合、処理をスキップし、次のユーザーに処理を移す

必要なファイルの用意

上記の流れで処理を行うので、以下のファイルが必要になります。
 削除するユーザー名を記載したテキストファイル
 削除処理を実行するシェルスクリプト

削除するユーザー名を記載したテキストファイル

今回使用するシェルスクリプトは、削除するIAMユーザー名が記載されたテキストファイルを1行ずつ読み込み、
取得したユーザー名を使用して削除処理を行います。
そのため、まずはこのテキストファイルを用意します。
以下のように、削除するIAMユーザー名が記載されたテキストファイルを用意します。
注意点として、改行コードはLF形式にします。
この形式にしないと、スクリプトでテキストファイルを正しく読み込めず、エラーが起きて処理に失敗します。

delete_users.txt
test-user1
test-user2
test-user3

(補足)LF形式の改行コードは、サクラエディタでテキストを開いたときに、改行部分が下矢印になります。
image.png

削除処理を行うシェルスクリプト

シェルスクリプトの内容は以下になります。

delete_users.sh
#!/bin/bash

deleteuserlist=$1

# 1.テキストファイルから削除ユーザー名を取得
while read -r USERNAME; do
    # 1-1.ユーザーの存在確認
    if aws iam get-user --user-name "$USERNAME" &> /dev/null; then
        # 1-1-1.ユーザーが存在する場合、以下の処理を実施
        echo "User Name: $USERNAME"

        # 1-1-1-1.ユーザーに紐づく署名用証明書を削除
        aws iam list-signing-certificates --user-name "$USERNAME" | jq -r '.Certificates[].CertificateId' | while read -r CERTIFICATE_ID; do
            aws iam delete-signing-certificate --user-name "$USERNAME" --certificate-id "$CERTIFICATE_ID"
            echo "ユーザー $USERNAME の署名用証明書を削除しました。"
        done

        # 1-1-1-2.ユーザーに紐づくGIt認証情報を削除
        aws iam list-service-specific-credentials --user-name "$USERNAME" | jq -r '.ServiceSpecificCredentials[].ServiceSpecificCredentialId' | while read -r GIT_CREDENTIAL_ID; do
            aws iam delete-service-specific-credential --user-name "$USERNAME" --service-specific-credential-id "$GIT_CREDENTIAL_ID"
            echo "ユーザー $USERNAME のGit認証情報を削除しました。"
        done

        # 1-1-1-3.ユーザーに紐づくSSHキーを削除
        aws iam list-ssh-public-keys --user-name "$USERNAME" | jq -r '.SSHPublicKeys[].SSHPublicKeyId' | while read -r SSH_KEY_ID; do
            aws iam delete-ssh-public-key --user-name "$USERNAME" --ssh-public-key-id "$SSH_KEY_ID"
            echo "ユーザー $USERNAME のSSHキーを削除しました。"
        done

        # 1-1-1-4.ユーザーに直接アタッチしたマネージドポリシーをデタッチ
        aws iam list-attached-user-policies --user-name "$USERNAME" | jq -r '.AttachedPolicies[].PolicyArn' | while read -r MANAGED_POLICY_ARN; do
            aws iam detach-user-policy --user-name "$USERNAME" --policy-arn "$MANAGED_POLICY_ARN"
            echo "ユーザー $USERNAME からマネージドポリシーをデタッチしました。"
        done

        # 1-1-1-5.ユーザーに直接アタッチしたインラインポリシーを削除
        aws iam list-user-policies --user-name "$USERNAME" | jq -r '.PolicyNames[]' | while read -r INLINE_POLICY_NAME; do
            aws iam delete-user-policy --user-name "$USERNAME" --policy-name "$INLINE_POLICY_NAME"
            echo "ユーザー $USERNAME からインラインポリシーを削除しました。"
        done


        # 1-1-1-6.グループからユーザーを除外
        aws iam list-groups-for-user --user-name "$USERNAME" | jq -r '.Groups[].GroupName' | while read -r GROUP_NAME; do
            aws iam remove-user-from-group --group-name "$GROUP_NAME" --user-name "$USERNAME"
            echo "グループからユーザー $USERNAME を削除しました。"
        done

        # 1-1-1-7.ユーザーに紐づくアクセスキー削除
        aws iam list-access-keys --user-name "$USERNAME" | jq -r '.AccessKeyMetadata[].AccessKeyId' | while read -r ACCESS_KEY_ID; do
            aws iam delete-access-key --user-name "$USERNAME" --access-key "$ACCESS_KEY_ID"
            echo "ユーザー $USERNAME のアクセスキーを削除しました。"
        done

        # 1-1-1-8.ユーザーに紐づくMFAデバイスの削除
        aws iam list-mfa-devices --user-name "$USERNAME" | jq -r '.MFADevices[].SerialNumber' | while read -r MFA_DEVICE_ARN; do
            aws iam deactivate-mfa-device --user-name "$USERNAME" --serial-number "$MFA_DEVICE_ARN"
            aws iam delete-virtual-mfa-device --serial-number "$MFA_DEVICE_ARN"
            echo "ユーザー $USERNAME のMFAデバイスを削除しました。"
        done

        # 1-1-1-9.ログインプロファイルの削除
        if result=$(aws iam delete-login-profile --user-name="$USERNAME" 2>&1); then
            echo "ユーザー $USERNAME のログインプロファイルを削除しました。"
        else
            # エラーメッセージを取得
            error_message=$(echo "$result" | grep -oP '(?<=An error occurred \().*(?=\))')

            # エラーメッセージが「NoSuchEntity」であればログインプロファイルが存在しない旨のメッセージを出力
            if [[ "$error_message" == "NoSuchEntity" ]]; then
                echo "ユーザー $USERNAME のログインプロファイルが存在しませんでした。ログインプロファイルの削除をスキップします。"
            else
                # その他のエラーの場合はエラーメッセージを表示し、シェルスクリプトの実行を終了
                echo "$error_message"
                echo "ユーザー $USERNAME のログインプロファイル削除で想定外のエラーが発生しました。処理を終了します。"
                exit 1
            fi
        fi

        # 1-1-1-10.ユーザーの削除
        aws iam delete-user --user-name "$USERNAME"
        echo "ユーザー $USERNAME を削除しました。"
    else
        # 1-1-2.ユーザーが存在しない場合は処理をスキップ
        echo "ユーザー $USERNAME は見つかりませんでした。削除スキップします。"
    fi
done < ./"$deleteuserlist".txt

echo "すべてのユーザーを削除しました。"

1-1-1-1 ~ 1-1-1-8の処理では、listコマンドとjqコマンドを組み合わせて、リソースを取得し、リソースが存在する場合のみ削除等の処理を行います。
IAMユーザーによっては、リソースが存在するものと存在しないものがあるため、リソースの存在確認を行った後、各リソースに応じた処理を行います。

1-1-1-9の処理について

1-1-1-9(ログインプロファイルの削除)は他とは違い、listコマンドが存在しないので、これだけは他リソースと異なるロジックで削除処理を行います。

まず、aws iam delete-login-profileコマンドを実行し、ログインプロファイルの削除を実行し、このコマンドの成功・失敗で条件分岐を行います。

sample.sh
# ログインプロファイルの削除
if result=$(aws iam delete-login-profile --user-name="$USERNAME" 2>&1); then
    echo "ユーザー $USERNAME のログインプロファイルを削除しました。"
else
    # ここにエラー発生時の処理を記載
fi

条件分岐する理由として、他リソースと同様、削除するユーザーにログインプロファイルが存在しない(つまりマネジメントコンソールにログインできない/しない)場合や、それ以外の要因でコマンドが失敗する可能性があるためです。

コマンド失敗時の処理では、ログインプロファイルが存在しない場合は削除処理をスキップし、それ以外の要因でエラーが起きた場合はスクリプトの処理を終了します。

これらの処理の流れをもう少し具体的に書くと以下になります。
 エラーメッセージを取得
 grepコマンドで"An error occurred ()"という文字列の括弧の間にあるエラーコードを抽出
 抽出したエラーコードが「NoSuchEntity」か確認(このコードはプロファイルが存在しないことを意味するエラーコードです)
  エラーコードが「NoSuchEntity」である場合
   ログインプロファイルが存在しないことを意味するので、ログインプロファイルの削除処理をスキップ
  エラーコードが「NoSuchEntity」でない場合(=他のエラーが発生した場合)
   エラーメッセージを表示し、スクリプトの処理を終了

sample.sh
# ログインプロファイルの削除
if result=$(aws iam delete-login-profile --user-name="$USERNAME" 2>&1); then
    echo "ユーザー $USERNAME のログインプロファイルを削除しました。"
else
    # エラーメッセージを取得
    error_message=$(echo "$result" | grep -oP '(?<=An error occurred \().*(?=\))')

    # エラーメッセージが「NoSuchEntity」であればログインプロファイルが存在しない旨のメッセージを出力
    if [[ "$error_message" == "NoSuchEntity" ]]; then
        echo "ユーザー $USERNAME のログインプロファイルが存在しませんでした。ログインプロファイルの削除をスキップします。"
    else
        # その他のエラーの場合はエラーメッセージを表示し、シェルスクリプトの実行を終了
        echo "$error_message"
        echo "ユーザー $USERNAME のログインプロファイル削除で想定外のエラーが発生しました。処理を終了します。"
        exit 1
    fi
fi

シェルスクリプトの実行

必要なファイルの用意ができたら、CloudShellでシェルスクリプトを実行します。

マネジメントコンソールにログインし、シェルスクリプトを開きます。
(下図赤枠ボタン)
image.png

シェルスクリプトを開いたら、アクション > ファイルのアップロードをクリックし、以下のファイルをアップロードします。
 ユーザーリストのテキストファイル
 IAMユーザー削除シェルスクリプト

image.png

アップロードしたシェルスクリプトファイルに、実行権限を付与します。

chmod +x delete_users.sh

実行権限が付与されていることを確認します。
(ユーザー権限に「x」が表示されている or ファイル名が緑色で表示されていればOK)
image.png

以下のコマンドを実行してシェルスクリプトの処理を実行します。
テキストファイル名は拡張子を除いた名前を指定します。
 ./<シェルスクリプトのファイル名> <削除ユーザーリストのテキストファイル名>

・コマンド例

./delete_users.sh delete_users

今回のシェルスクリプトでは以下のようなメッセージが表示されます。
最後に「すべてのユーザーを削除しました。」と表示されれば処理終了です。

User Name: test-user1
ユーザー test-user1 の署名用証明書を削除しました。
ユーザー test-user1 のGit認証情報を削除しました。
ユーザー test-user1 のSSHキーを削除しました。
ユーザー test-user1 のアクセスキーを削除しました。
ユーザー test-user1 のログインプロファイルを削除しました。
ユーザー test-user1 を削除しました。
User Name: test-user2
ユーザー test-user2 の署名用証明書を削除しました。
ユーザー test-user2 の署名用証明書を削除しました。
ユーザー test-user2 のGit認証情報を削除しました。
ユーザー test-user2 のGit認証情報を削除しました。
ユーザー test-user2 からマネージドポリシーをデタッチしました。
ユーザー test-user2 からマネージドポリシーをデタッチしました。
ユーザー test-user2 からインラインポリシーを削除しました。
ユーザー test-user2 からインラインポリシーを削除しました。
グループからユーザー test-user2 を削除しました。
グループからユーザー test-user2 を削除しました。
ユーザー test-user2 のアクセスキーを削除しました。
ユーザー test-user2 のアクセスキーを削除しました。
ユーザー test-user2 のMFAデバイスを削除しました。
ユーザー test-user2 のログインプロファイルを削除しました。
ユーザー test-user2 を削除しました。
User Name: test-user3
ユーザー test-user3 のログインプロファイルが存在しませんでした。ログインプロファイルの削除をスキップします。
ユーザー test-user3 を削除しました。
すべてのユーザーを削除しました。

コンソール画面上に、削除したユーザーが表示されていなければOKです。
image.png

参考資料

ログインプロファイル削除失敗時のエラーコード取得では、正規表現でのgrepコマンドの先読み・後読みを使用しています。
これらの仕組みについては、以下の記事が参考になります。

AWS CLIによるIAMユーザー削除の流れは以下記事をご参考ください。
記事には、各コマンドのリファレンスのリンクもあるので、コマンドの仕様も確認できます。

1
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
1
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?