0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第8編】検証で作成したAWS S3・Glue・IAM環境を安全に削除してみる

0
Last updated at Posted at 2026-09-20

はじめに

これまでのseriesでは、HDFS上のrawログとApache IcebergをAmazon S3へ移行し、AWS Glue Data Catalog、Spark、Flink、Trino、Grafana、Zeppelinから利用する構成を作成した。

本記事では、実機検証後にAWS環境を残さない場合の削除手順をまとめる。ただし本seriesでは、これまでの記事で作成したS3 Raw backupとS3 Icebergを継続利用するため、これらのbucket、Glue database/table、Athena workgroup、home-rawlog-backup、home-aws、home-aws-adminは削除しない。

本seriesの標準経路ではAmazon S3を継続利用するため、S3/Glue削除手順は実施しない。本記事の対象は、別途作成した検証専用resourceだけである。

AWS環境の削除は復旧できない操作を含む。特にS3のobject versionを完全削除すると、versioningを有効にしていても復元できない。commandをそのまま実行せず、AWS account ID、region、resource名、共有利用の有無を確認し、削除承認を得てから実施する。

今回削除するもの

このseriesで作成した可能性があるresourceは次のとおりである。

resource 例 削除条件
S3 raw bucket <YOUR_UNIQUE_RAW_BUCKET> 検証専用で、他jobが読み書きしていない
S3 Iceberg bucket <YOUR_UNIQUE_ICEBERG_BUCKET> Iceberg、checkpoint、savepointを含めて不要
Glue Database logs 既存databaseではなく検証専用
Glue Table syslog_icebergなど 他systemから参照されていない
IAM user / role Spark、Flink、Trino、Connect用 検証専用principalである
IAM policy 対象bucket・Glue用policy 他principalへattachされていない
Access key 検証用IAM userのkey 該当user専用である
KMS key 任意で作成したcustomer managed key 検証専用で、他dataを暗号化していない
Athena query result 検証で生成した結果 専用prefixまたは専用bucketである

次は、このseriesでは新規作成していないため自動的に削除対象にしない。

  • AWS account、Organization、VPC
  • 既存のCloudTrail、AWS Config、GuardDuty
  • 共有のIAM role、IAM policy、KMS key
  • 既存のAthena query result bucket
  • 他systemと共有しているGlue Database
  • backup、監査、法令保持のために必要なS3 object

削除の順序

依存関係を考慮して、次の順で削除する。

1. 削除対象を固定する
2. Kafka Connect / Spark / Flinkなどのwriterを停止する
3. 最終backupとresource一覧を保存する
4. Trino / Grafana / Zeppelinなどのreaderを切り離す
5. Glue TableとDatabaseを削除する
6. S3 multipart uploadを中止する
7. S3の全object versionとdelete markerを削除する
8. 空になったS3 bucketを削除する
9. 検証専用IAM credential、user、role、policyを削除する
10. 検証専用KMS keyがあれば削除をscheduleする
11. local hostのAWS設定を撤去する
12. resourceと料金が残っていないことを確認する

IAM principalは、S3とGlueを削除するための最後のAPI callが終わるまで残す。

1. 対象accountとresourceを固定する

最初に変数を設定する。placeholderを実在するresource名へ置き換え、実行前に表示内容を確認する。

export AWS_REGION='ap-northeast-1'
export AWS_PROFILE='home-aws-admin'
source /etc/rawlog-s3-backup/common.env
export PRESERVE_RAW_BUCKET="${S3_BUCKET_NAME}"
source /etc/iceberg/aws.env
export PRESERVE_ICEBERG_BUCKET="${ICEBERG_BUCKET}"
export AWS_RAW_BUCKET='<DELETE_ONLY_IF_SEPARATE_TEST_BUCKET>'
export AWS_ICEBERG_BUCKET='<DELETE_ONLY_IF_SEPARATE_TEST_BUCKET>'

AWS_RAW_BUCKETまたはAWS_ICEBERG_BUCKETがPRESERVE_RAW_BUCKET、PRESERVE_ICEBERG_BUCKETのいずれかと一致した場合は、以降の削除を中止する。

for delete_bucket in "${AWS_RAW_BUCKET}" "${AWS_ICEBERG_BUCKET}"; do
  case "${delete_bucket}" in
    "${PRESERVE_RAW_BUCKET}"|"${PRESERVE_ICEBERG_BUCKET}")
      printf 'ERROR: backup bucket is protected: %s\n' "${delete_bucket}" >&2
      return 1 2>/dev/null || exit 1
      ;;
  esac
done

caller identityを確認する。

aws sts get-caller-identity \
  --profile "${AWS_PROFILE}" \
  --region "${AWS_REGION}"

表示されたAccountが想定する検証用AWS account IDと一致しない場合は中止する。

対象bucketのregion、versioning、Object Lockを確認する。

for bucket in "${AWS_RAW_BUCKET}" "${AWS_ICEBERG_BUCKET}"; do
  echo "===== ${bucket} ====="

  aws s3api get-bucket-location \
    --bucket "${bucket}" \
    --profile "${AWS_PROFILE}"

  aws s3api get-bucket-versioning \
    --bucket "${bucket}" \
    --profile "${AWS_PROFILE}"

  aws s3api get-object-lock-configuration \
    --bucket "${bucket}" \
    --profile "${AWS_PROFILE}" || true
done

Object Lockのretentionまたはlegal holdで保護されたversionは、保持条件を満たすまで完全削除できない。AccessDeniedを回避するために保護を迂回するのではなく、保持期限と組織のdata retention policyを確認して削除を延期する。

Glue DatabaseとTableを確認する。

aws glue get-database \
  --name "${GLUE_DATABASE}" \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

aws glue get-tables \
  --database-name "${GLUE_DATABASE}" \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}" \
  --query 'TableList[].{Name:Name,Location:StorageDescriptor.Location}' \
  --output table

table locationに今回のbucket以外が含まれる場合、Database全体を削除しない。検証用Tableだけを個別に削除する。

2. AWSへ書き込む処理を停止する

削除中にobjectやGlue metadataが再作成されないよう、writerを先に停止する。

Kafka Connect S3 Sinkを停止する

対象connectorを確認してpauseする。

curl -fsS http://connect1:8083/connectors | jq

curl -fsS -X PUT \
  http://connect1:8083/connectors/s3-syslog-sink/pause

curl -fsS -X PUT \
  http://connect1:8083/connectors/s3-authlog-sink/pause

Sparkのバッチ処理を停止する

AWS S3へ書き込むcronとsystemd timerを停止する。

systemctl list-timers --all | rg -i 'spark|iceberg|log'

実際のunit名を確認し、対象timerだけを停止する。

Flink

対象job IDを確認し、今後復旧する可能性がある場合はfinal savepointをAWS以外の保持先へ取得してから停止する。

sudo -u flink /opt/flink/current/bin/flink list -a

AWS環境そのものを削除する場合、削除対象bucket内のsavepointはrollbackに利用できない。必要なsavepointは別の保存先へ退避する。

Trino、Athena、Grafana、Zeppelin

readerはdataを作らないが、削除中の誤参照を防ぐため、次を実施する。

  • Trinoのiceberg_aws catalogを利用する定期queryを停止する
  • GrafanaのAWS版dashboardを無効化する
  • Zeppelinのtrino_aws Notebookを停止またはread-onlyにする
  • Athenaのscheduled queryを停止する

3. 最終backupと証跡を取得する

削除後に必要となる可能性がある情報を保存する。

aws s3 ls "s3://${AWS_RAW_BUCKET}/" \
  --recursive --summarize \
  --profile "${AWS_PROFILE}"

aws s3 ls "s3://${AWS_ICEBERG_BUCKET}/" \
  --recursive --summarize \
  --profile "${AWS_PROFILE}"

Glue Table定義をJSONで取得する。

aws glue get-tables \
  --database-name "${GLUE_DATABASE}" \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}" \
  --output json > glue-tables-before-delete.json

次も削除記録へ残す。

  • AWS account IDとregion
  • bucket名とobject/version数
  • Glue Database/Table名
  • IAM principalとpolicy ARN
  • KMSキーのARN
  • writerを停止した時刻
  • backupの保存先と復元確認結果
  • 削除承認者と作業日時

backupを同じ削除対象bucketへ置かない。

4. Glue Data Catalogを削除する

GlueのTableを削除しても、S3上のIceberg data fileやmetadata fileは削除されない。先にcatalog metadataを削除し、その後S3を個別に空にする。

検証専用Tableだけを削除する場合

対象を表示してから、1 tableずつ削除する。

aws glue get-tables \
  --database-name "${GLUE_DATABASE}" \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}" \
  --query 'TableList[].Name' \
  --output table
aws glue delete-table \
  --database-name "${GLUE_DATABASE}" \
  --name '<DELETE_TARGET_TABLE>' \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

今回の例では、次のようなTableが候補になる。ただし、存在確認と所有者確認なしに一括削除しない。

syslog_iceberg
authlog_iceberg
syslog_events
authlog_events
syslog_host_1m
authlog_host_1m

Database全体を削除する場合

logsが検証専用で、全Tableを削除してよい場合だけ実行する。

aws glue delete-database \
  --name "${GLUE_DATABASE}" \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

Glue Databaseを削除すると、所属するTable、Table Version、Partitionなどへアクセスできなくなり、関連metadataは非同期削除される。即時に個別resourceを消す必要がある場合は、AWS公式手順に従ってTable VersionやPartitionを先に削除する。

5. 未完了multipart uploadを削除する

未完了multipart uploadのpartにもstorage料金が発生する。各bucketで一覧を確認する。

for bucket in "${AWS_RAW_BUCKET}" "${AWS_ICEBERG_BUCKET}"; do
  aws s3api list-multipart-uploads \
    --bucket "${bucket}" \
    --profile "${AWS_PROFILE}" \
    --query 'Uploads[].{Key:Key,UploadId:UploadId,Initiated:Initiated}' \
    --output table
done

削除対象bucketであることを再確認し、各uploadを中止する。

aws s3api abort-multipart-upload \
  --bucket '<DELETE_TARGET_BUCKET>' \
  --key '<OBJECT_KEY>' \
  --upload-id '<UPLOAD_ID>' \
  --profile "${AWS_PROFILE}"

一覧が空になるまで確認する。upload中のwriterが残っている場合は、先にwriterを特定する。

6. versioning有効bucketを空にする

本seriesではS3 Versioningを有効にしている。次のcommandだけでは、current objectにdelete markerが追加されるだけで、過去versionは残る。

aws s3 rm "s3://<BUCKET>/" --recursive

bucketを完全に削除するには、すべてのobject versionとdelete markerをversion ID付きで削除する必要がある。

削除前の件数を確認する

for bucket in "${AWS_RAW_BUCKET}" "${AWS_ICEBERG_BUCKET}"; do
  echo "===== ${bucket} ====="

  aws s3api list-object-versions \
    --bucket "${bucket}" \
    --profile "${AWS_PROFILE}" \
    --query '{Versions:length(Versions),DeleteMarkers:length(DeleteMarkers)}'
done

全versionとdelete markerを削除する

次は、指定した1 bucketのversionとdelete markerを最大1,000件ずつ削除する例である。実行前にDELETE_BUCKETを表示し、AWS account IDと照合する。

export DELETE_BUCKET='<EXACT_BUCKET_NAME_APPROVED_FOR_DELETION>'

printf 'DELETE_BUCKET=%s\n' "${DELETE_BUCKET}"
aws sts get-caller-identity --profile "${AWS_PROFILE}"
aws s3api get-bucket-versioning \
  --bucket "${DELETE_BUCKET}" \
  --profile "${AWS_PROFILE}"

一覧をlocal fileへ保存し、削除予定件数を確認する。

aws s3api list-object-versions \
  --bucket "${DELETE_BUCKET}" \
  --profile "${AWS_PROFILE}" \
  --output json > "${DELETE_BUCKET}-versions.json"

jq '{
  versions: (.Versions // [] | length),
  delete_markers: (.DeleteMarkers // [] | length)
}' "${DELETE_BUCKET}-versions.json"

承認後、versionとdelete markerを1,000件単位で削除する。

jq -c '
  [(.Versions // [])[], (.DeleteMarkers // [])[]]
  | map({Key: .Key, VersionId: .VersionId})
  | range(0; length; 1000) as $offset
  | {Objects: .[$offset:$offset + 1000], Quiet: true}
' "${DELETE_BUCKET}-versions.json" |
while IFS= read -r delete_request; do
  aws s3api delete-objects \
    --bucket "${DELETE_BUCKET}" \
    --delete "${delete_request}" \
    --profile "${AWS_PROFILE}"
done

削除処理中にwriterが残っていた場合や、一覧取得後にobjectが作成された場合はversionが残る。再度一覧を取得し、VersionsとDeleteMarkersの両方が空になるまで確認する。

aws s3api list-object-versions \
  --bucket "${DELETE_BUCKET}" \
  --profile "${AWS_PROFILE}" \
  --query '{Versions:Versions,DeleteMarkers:DeleteMarkers}'

大量のobjectを含む本番規模bucketでは、このshell例をそのまま使わない。S3 Lifecycle、S3 Batch Operations、AWS Supportへの相談を含め、削除時間、API request料金、Object Lock、replicationを考慮した削除計画を作る。

7. S3 bucketを削除する

全version、delete marker、multipart uploadが存在しないことを確認してからbucketを削除する。

aws s3api delete-bucket \
  --bucket '<EXACT_EMPTY_BUCKET_NAME>' \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

raw bucketとIceberg bucketを別々に確認して実施する。BucketNotEmptyが返った場合は、通常objectだけでなく、過去version、delete marker、multipart uploadを再確認する。

削除確認を行う。

aws s3api head-bucket \
  --bucket '<DELETED_BUCKET_NAME>' \
  --profile "${AWS_PROFILE}"

削除後は404が想定結果である。403の場合は、bucket名が他accountで再利用された可能性や権限不足を区別できないため、AWS Consoleとresource一覧でも確認する。

8. 検証専用IAM resourceを削除する

IAM resourceはS3とGlueの削除確認後に処理する。共有roleや共有policyは削除しない。

Access keyを無効化してから削除する

対象userとkeyを確認する。

aws iam list-access-keys \
  --user-name '<DELETE_TARGET_USER>' \
  --profile "${AWS_PROFILE}"

まず無効化し、利用者がいないことを確認する。

aws iam update-access-key \
  --user-name '<DELETE_TARGET_USER>' \
  --access-key-id '<ACCESS_KEY_ID>' \
  --status Inactive \
  --profile "${AWS_PROFILE}"

観察後に削除する。

aws iam delete-access-key \
  --user-name '<DELETE_TARGET_USER>' \
  --access-key-id '<ACCESS_KEY_ID>' \
  --profile "${AWS_PROFILE}"

IAM userを削除する

userを削除する前に、attached policy、inline policy、group、login profile、service-specific credentialなどを確認して削除する必要がある。

aws iam list-attached-user-policies \
  --user-name '<DELETE_TARGET_USER>' \
  --profile "${AWS_PROFILE}"

aws iam list-user-policies \
  --user-name '<DELETE_TARGET_USER>' \
  --profile "${AWS_PROFILE}"

aws iam list-groups-for-user \
  --user-name '<DELETE_TARGET_USER>' \
  --profile "${AWS_PROFILE}"

すべての関連resourceを外した後、検証専用userを削除する。

aws iam delete-user \
  --user-name '<DELETE_TARGET_USER>' \
  --profile "${AWS_PROFILE}"

IAM roleとcustomer managed policy

roleはinstance profile、attached policy、inline policyを確認する。policyは他principalへのattachmentと全default以外のversionを確認する。

aws iam list-entities-for-policy \
  --policy-arn '<DELETE_TARGET_POLICY_ARN>' \
  --profile "${AWS_PROFILE}"

他principalが表示されたpolicyは削除しない。検証専用であることを確認してからdetach、role/user削除、policy削除の順で処理する。

9. 検証専用KMS keyを削除する

SSE-S3のAES256だけを使用した場合、customer managed KMS keyは作成されていないため、この作業は不要である。

SSE-KMS用に検証専用keyを作成した場合は、他bucket、CloudWatch Logs、Secrets Managerなどが利用していないことを確認する。KMS keyの削除は即時ではなく、待機期間を指定してscheduleする。

aws kms describe-key \
  --key-id '<DELETE_TARGET_KMS_KEY_ARN>' \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

検証専用であることを承認後、AWSの許容範囲内で待機期間を指定する。

aws kms schedule-key-deletion \
  --key-id '<DELETE_TARGET_KMS_KEY_ARN>' \
  --pending-window-in-days 30 \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

共有keyをschedule deletionすると、他dataを復号できなくなる。key policy、aliasだけで判断せず、利用resourceを確認する。

10. local側のAWS設定を撤去する

AWS resource削除後、各serviceに残るcredentialと設定を撤去する。

service 確認するもの
Kafka Connect S3 Sink connector、AWS EnvironmentFile、S3 Sink plugin
Spark AWS profile、Glue catalog設定、hadoop-aws依存
Flink AWS profile、EnvironmentFile、S3 checkpoint設定、Iceberg AWS bundle
Trino iceberg_aws.properties、AWS EnvironmentFile
Zeppelin trino_aws Interpreter、AWS用Notebook
rclone AWS remoteとcredential

設定fileを削除する前に、他のAWS workloadが同じcredentialやlibraryを使っていないことを確認する。

特に次は自動的に削除しない。

  • Sparkが別のs3a://を利用している場合のhadoop-aws
  • Flinkが別のS3 checkpointを利用している場合のS3 filesystem plugin
  • Trinoが別のAWS catalogを利用している場合のAWS credential
  • 共有Kafka Connect workerのS3 Sink plugin

11. 削除結果を確認する

Glue

aws glue get-database \
  --name "${GLUE_DATABASE}" \
  --region "${AWS_REGION}" \
  --profile "${AWS_PROFILE}"

Database全体を削除した場合、EntityNotFoundExceptionが想定結果になる。Tableだけ削除した場合は、get-tablesで対象Tableがないことを確認する。

S3

aws s3api list-buckets \
  --profile "${AWS_PROFILE}" \
  --query 'Buckets[].Name' \
  --output text

削除対象bucket名が表示されないことを確認する。

IAM

aws iam get-user \
  --user-name '<DELETED_USER>' \
  --profile "${AWS_PROFILE}"

aws iam get-role \
  --role-name '<DELETED_ROLE>' \
  --profile "${AWS_PROFILE}"

対象を削除した場合、NoSuchEntityが想定結果になる。

料金

Cost Explorer、S3 Storage Lens、Billing画面で次を確認する。

  • S3 current/noncurrent versionのstorage
  • incomplete multipart uploadのstorage
  • S3 APIリクエスト
  • Glue Data Catalogの利用量
  • KMS key
  • データ転送
  • CloudWatch Logsなど周辺resource

Cost Explorerなどの反映には時間差があるため、削除直後だけでなく翌日以降も確認する。

削除できない場合の確認表

症状 主な原因 確認
BucketNotEmpty 過去version、delete marker、multipart upload list-object-versions、list-multipart-uploads
AccessDenied IAM不足、bucket policy、Object Lock caller identity、policy、retention、legal hold
objectが再作成される writerが残っている Connect、Spark timer、Flink job、scheduled query
Glue Table削除後もS3容量が残る Glue削除はdata fileを削除しない S3 version一覧
IAM userを削除できない key、policy、group等が残っている IAMの関連resource一覧
KMS keyを削除できない 待機期間、共有利用、権限 key state、key policy、利用resource

まとめ

AWS検証環境の削除では、S3 bucketだけを削除しようとしても完了しない。本seriesではversioningを有効にしているため、current object、noncurrent version、delete marker、multipart uploadをすべて確認する必要がある。

削除順序は、writer停止、backup、Glue、S3 data、S3 bucket、IAM、KMS、local設定とする。IAM credentialを先に消すと後続の削除ができず、writerを止めずにS3を空にするとobjectが再作成される。

本番移行先としてAWSを利用し続ける場合は、この削除手順を実行しない。検証専用resourceと共有resourceを明確に分け、account ID、region、resource名、Object Lock、backup、承認を確認してから削除する。

参考資料

関連記事

実機検証について

本記事の削除手順は、執筆時点では実機環境での一連の動作検証をまだ完了していない。掲載commandにはresourceを完全削除する操作が含まれるため、検証用AWS accountまたは隔離された専用resourceで確認する必要がある。

実施する場合は、削除対象一覧、backup、restore手順、Object Lock、共有利用の有無を確認し、複数名で承認した正確なresource名だけを対象にする。実機検証の結果に応じて本記事を更新する予定である。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?