はじめに
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形式にします。
この形式にしないと、スクリプトでテキストファイルを正しく読み込めず、エラーが起きて処理に失敗します。
test-user1
test-user2
test-user3
(補足)LF形式の改行コードは、サクラエディタでテキストを開いたときに、改行部分が下矢印になります。
削除処理を行うシェルスクリプト
シェルスクリプトの内容は以下になります。
#!/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コマンドを実行し、ログインプロファイルの削除を実行し、このコマンドの成功・失敗で条件分岐を行います。
# ログインプロファイルの削除
if result=$(aws iam delete-login-profile --user-name="$USERNAME" 2>&1); then
echo "ユーザー $USERNAME のログインプロファイルを削除しました。"
else
# ここにエラー発生時の処理を記載
fi
条件分岐する理由として、他リソースと同様、削除するユーザーにログインプロファイルが存在しない(つまりマネジメントコンソールにログインできない/しない)場合や、それ以外の要因でコマンドが失敗する可能性があるためです。
コマンド失敗時の処理では、ログインプロファイルが存在しない場合は削除処理をスキップし、それ以外の要因でエラーが起きた場合はスクリプトの処理を終了します。
これらの処理の流れをもう少し具体的に書くと以下になります。
エラーメッセージを取得
grepコマンドで"An error occurred ()"という文字列の括弧の間にあるエラーコードを抽出
抽出したエラーコードが「NoSuchEntity」か確認(このコードはプロファイルが存在しないことを意味するエラーコードです)
エラーコードが「NoSuchEntity」である場合
ログインプロファイルが存在しないことを意味するので、ログインプロファイルの削除処理をスキップ
エラーコードが「NoSuchEntity」でない場合(=他のエラーが発生した場合)
エラーメッセージを表示し、スクリプトの処理を終了
# ログインプロファイルの削除
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でシェルスクリプトを実行します。
マネジメントコンソールにログインし、シェルスクリプトを開きます。
(下図赤枠ボタン)
シェルスクリプトを開いたら、アクション > ファイルのアップロードをクリックし、以下のファイルをアップロードします。
ユーザーリストのテキストファイル
IAMユーザー削除シェルスクリプト
アップロードしたシェルスクリプトファイルに、実行権限を付与します。
chmod +x delete_users.sh
実行権限が付与されていることを確認します。
(ユーザー権限に「x」が表示されている or ファイル名が緑色で表示されていればOK)
以下のコマンドを実行してシェルスクリプトの処理を実行します。
テキストファイル名は拡張子を除いた名前を指定します。
./<シェルスクリプトのファイル名> <削除ユーザーリストのテキストファイル名>
・コマンド例
./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です。
参考資料
ログインプロファイル削除失敗時のエラーコード取得では、正規表現でのgrepコマンドの先読み・後読みを使用しています。
これらの仕組みについては、以下の記事が参考になります。
AWS CLIによるIAMユーザー削除の流れは以下記事をご参考ください。
記事には、各コマンドのリファレンスのリンクもあるので、コマンドの仕様も確認できます。