Control Tower 有効化で作成される AggregateSecurityNotifications のSNSサブスクリプションを削除する
はじめに(モチベーション)
[前提] AggregateSecurityNotifications とは
AWS Control Tower(以降 CT) を新規に有効化すると、 監査アカウント上に aws-controltower-AggregateSecurityNotifications という SNSトピックが自動生成されます。 これはコンプライアンス変更通知(主にConfig)を受け取るために CT側で用意されたものです。
AggregateSecurityNotifications トピック は CT管理のリージョン上にそれぞれ配置され、 デフォルトで『 監査アカウントのメールアドレスへのサブスクリプション 』も作成されます。
AggregateSecurityNotifications は「非常にノイズが多い」
さて、この AggregateSecurityNotifications ですが、 公式ドキュメントにもあるとおり 意図的に非常にノイズが多い ものとなっています。
AWS Control Tower の SNS トピックは、意図的に非常にノイズの多いものとなっています。 例えば、AWS Config は、AWS Config が新しいリソースを検出するたびに通知を送信します。
仮に送信されてくるメールの Confirm subscription を押下すると、 大量に通知が来ることになります。
メーリングリストなど複数メンバーが見れるような環境下だと、 誤って押下してしまう可能性も高まります。
このサブスクリプションを「完全に」削除したい
そのため、デフォルトで作成されるサブスクリプションは「完全に」削除してしまいたいです。
ただし、SNSトピックにはいくつか制約(↓)があり一筋縄ではいきません。
- 保留中(PendingConfirmation)の サブスクリプションは強制的に削除できない
- メールから unsubscribe したとしても、再度サブスクライブできてしまう
- 完全にサブスクリプションを削除するには API(AWS CLI等) から実行しないといけない
これら制約下でなんとかやりくりした方法を本ブログで紹介します。
手順
前提
本作業は Control Tower 有効化が完了した後に実施します。
メールで届く Confirm subscription を全て押下する
Control Tower 有効化後に送られてくる 「AWS Notification - Subscription Confirmation」 のメールを確認します。 メールボックスにて ${AuditアカウントID}:aws-controltower-AggregateSecurityNotifications
といったワードで検索すると見つけやすいです。
「Control Tower 管理のリージョン分」 で Confirm subscription メールが届いているはずです。 それら全ての Confirmリンクを押下します。
管理アカウントの CloudShell を起動する
管理アカウントへログインして、CloudShell を起動させます。
Auditアカウントへスイッチロールする
前提として、Control Tower には 「管理アカウントから Auditアカウントの AWSControlTowerExecution ロール
へスイッチロールできる経路」 が標準で用意されています。
これを用いて Auditアカウントへスイッチロールします。 以下コマンドを実行してください。 (audit_account_id
の値部分を置き換えて実行します)
audit_account_id=123456789012 resp=$(aws sts assume-role --output json \ --role-arn arn:aws:iam::${audit_account_id}:role/AWSControlTowerExecution \ --role-session-name cm-initial-setup) export AWS_ACCESS_KEY_ID=$(echo "$resp" | jq -r ".Credentials.AccessKeyId") export AWS_SECRET_ACCESS_KEY=$(echo "$resp" | jq -r ".Credentials.SecretAccessKey") export AWS_SESSION_TOKEN=$(echo "$resp" | jq -r ".Credentials.SessionToken")
実行後、 sts get-caller-identity
結果を出力します。 Auditアカウントへスイッチロールできていることを確認してください。
aws sts get-caller-identity # { # "UserId": "AROAEXAMPLE:cm-initial-setup", # "Account": "${AuditアカウントID}", # "Arn": "arn:aws:sts::${AuditアカウントID}:assumed-role/AWSControlTowerExecution/cm-initial-setup" # }
サブスクリプションを削除する
以下コマンドを実行して、削除対象のサブスクリプションを削除します。
## 全リージョンで AggregateSecurityNotifications トピックをチェックする aws ec2 describe-regions --query "Regions[].[RegionName]" --output text \ | while read region; do echo "### ${region}" ## 対象トピックが存在しない場合は continue ct_topic_arn=$(aws sns list-topics --region "${region}" --output text \ --query 'Topics[?ends_with(TopicArn, `:aws-controltower-AggregateSecurityNotifications`)].TopicArn') if [[ "$ct_topic_arn" = "" ]]; then echo "- The topic is not found in ${region}" continue fi ## 対象トピックのサブスクリプションが存在しない場合は continue echo "- ${ct_topic_arn} found" ct_subscriptions=$(aws sns list-subscriptions-by-topic --region "${region}" --output text \ --topic-arn ${ct_topic_arn} --query "Subscriptions[].[Endpoint, SubscriptionArn]") if [[ "$ct_subscriptions" = "" ]]; then echo " - No subscriptions" continue fi ## サブスクリプションを削除する echo "$ct_subscriptions" \ | while read sub_endpoint sub_arn; do ## サブスクライブ済みであれば、サブスクライブを削除する if [[ "$sub_arn" == arn:aws:sns:* ]]; then echo " - deleting subscription: ${sub_arn} (${sub_endpoint})" aws sns unsubscribe --region "${region}" --subscription-arn "${sub_arn}" ## サブスクライブ済みでない場合は何もしない else echo " - skipped, because subscription status is ${sub_arn} (${sub_endpoint})" fi done done
以降使っているAWSコマンドの説明です。
ec2 describe-region
aws ec2 describe-regions --query "Regions[].[RegionName]" --output text # ap-south-1 # eu-north-1 # eu-west-3 # ...略
全リージョンのSNSトピック(サブスクリプション)を確認するために使用しています。
sns list-topics
aws sns list-topics --region "${region}" --output text \ --query 'Topics[?ends_with(TopicArn, `:aws-controltower-AggregateSecurityNotifications`)].TopicArn' # arn:aws:sns:${region}:123456789012:aws-controltower-AggregateSecurityNotifications
aws-controltower-AggregateSecurityNotifications
SNSトピックが無いか確認します。 queryオプションを使ってフィルターしています。
sns list-subscriptions-by-topic
aws sns list-subscriptions-by-topic --region "${region}" --output text \ --topic-arn ${ct_topic_arn} --query "Subscriptions[].[Endpoint, SubscriptionArn]" # (subscribe した場合) → audit@example.com arn:aws:sns:${region}:123456789012:aws-controltower-AggregateSecurityNotifications:b75116c0-47a4-4df6-819a-517example # (保留中の場合) → audit@example.com PendingConfirmation # (メールから unsubscribe した場合) → audit@example.com Deleted
aws-controltower-AggregateSecurityNotifications
SNSトピックのサブスクリプションをリストします。
sns unsubscribe
## サブスクライブ済みであれば、サブスクライブを削除する if [[ "$sub_arn" == arn:aws:sns:* ]]; then echo " - deleting subscription: ${sub_arn} (${sub_endpoint})" aws sns unsubscribe --region "${region}" --subscription-arn "${sub_arn}" ## サブスクライブ済みでない場合は何もしない else echo " - skipped, because subscription status is ${sub_arn} (${sub_endpoint})" fi
サブスクリプションを AWS CLIから削除します。 これにより再度 subscribe されることは無くなります。
注意ですが、サブスクリプション削除( aws sns unsubscribe
) は PendingConfirmation および Deleted 状態のものは消せません 。 そのため if-else を使って条件分岐させています。
おわりに
以上、AggregateSecurityNotifications のSNSサブスクリプションを「完全に」削除する手順の紹介でした。
ちなみに 保留中のSNSトピックは、 48時間後に自動削除されます。
「48時間待って、完全削除とする」でももちろん良いのですが、 その間に誰かが Confirm subscription を押してしまうといけないので難しいところです。
本ブログが参考になれば幸いです。