こんにちは、ひるたんぬです。
最近は暑い日が続いていますね。私はこの時季になると冷房が欠かせないものとなっています。
世間では「春と秋がどんどん短くなっている」と言われており、私もそう思っていたのですが、具体的にどれだけ短くなっているのでしょうか?
調べてみると、そもそも春夏秋冬の絶対的な定義というものは存在しないようです。
気象学や天文学、伝統的な区切り方がそれぞれあるようですね。
こうなると、「私にとっての春」と「未来の人にとっての春」のイメージは大きく異なるものになりそうですね。
ひまわりは春の花、が常識になる日も…?
※ 参考…国立天文台 | 暦Wiki「季節とは?」
さて、今回は標準ユーザーが管理者権限を持つユーザーに昇格した場合に、そのアクティビティをAmazon SNSを用いて通知する方法をご紹介します。
やりたいこと
Windows OSにおいて管理者権限を持たないユーザーが、管理者権限を持つユーザーに昇格した場合に、他の管理者に通知したい場合を想定しています。今回のWindows OSはWorkSpaces上で稼働している想定ですが、WorkSpacesに限らず、どこでも通用するかなと思います。
やり方
ここからは、実際にどのように設定していくかをご紹介していきます。
事前準備
通知先のAmazon SNSトピック・サブスクリプションを作成します。
今回はメールでの通知を設定しています。
また、後述するスクリプトがメッセージを送信できるようにIAMユーザーとアクセスキーを作成します。
最小権限の原則から、当該トピックでのSNSメッセージ送信のみ許可されたIAMユーザーを新しく作成することを推奨します。
今回はこれら事前準備の手順は割愛します。詳細は公式ドキュメントなどをご参照ください。
なにをトリガーにするか
今回の肝となるのは、「どのように管理者権限を持つユーザーに昇格したことを知るか」です。
調べてみると、これはWindows ログのイベントとしてログが記録されることが分かりました。
今回はこの中でも「セキュリティ」の中に記録されているイベントIDが4648のログに着目します。
このログは明示的な資格情報を使用したサインインを記録するもので、RUNASなどの昇格操作を実施した際に記録されるものです。
実際に昇格操作を実施したところ、確かにログが記録されることを確認したので、今回はこのイベントIDのログを利用することにします。
Amazon SNSでの通知スクリプト
トリガーを受けての操作として、Amazon SNSを用いた通知を行います。今回はこの部分をPowerShellのスクリプトで作成しました。
今回は「admin」という名前を含むユーザーに昇格した場合に通知をするという内容にしています。
関数の引数はIAMの認証情報と、通知先のSNSトピックのARNが必須で必要です。適宜付与するようにしてください。
また、エラー処理などはすべて省いております。
function Get-AdminAlert { param ( [Parameter(Mandatory = $true)] [string]$AccessKey, [Parameter(Mandatory = $true)] [string]$SecretKey, [Parameter(Mandatory = $true)] [string]$TopicArn, [Parameter(Mandatory = $false)] [string]$Region = "ap-northeast-1" ) # AWS CLI用の環境変数を設定 $env:AWS_ACCESS_KEY_ID = $AccessKey $env:AWS_SECRET_ACCESS_KEY = $SecretKey $env:AWS_DEFAULT_REGION = $Region # イベントログから管理者に昇格しているログを抽出 $admin_name = "admin" $now = Get-Date # 発火時から30秒以内の該当イベントログを取得 $eventlog = Get-EventLog -LogName Security -Newest 1 -EntryType SuccessAudit -InstanceId 4648 -Message *$admin_name* -After $now.Addseconds(-30) if ($eventlog -eq $null) { Write-Host "No relevant event logs found." -ForegroundColor Yellow return $false } # Message内を処理するため、Jsonに変換後PowerShellオブジェクトに変換 $eventlog_json = $eventlog | ConvertTo-Json $eventlog_object = ConvertFrom-Json $eventlog_json # 昇格先アカウント名を抽出 $admin_account = $eventlog_object.ReplacementStrings[5] if ($admin_account -eq $null) { $admin_account = "Unknown" Write-Host "No admin account found in the event log." } # イベント発生日時を抽出(UTC) $eventtime = $eventlog_object.TimeGenerated # イベント発生日時を日本時間に変換 $eventtime_jst = $eventtime.ToUniversalTime().AddHours(9) # SNSメッセージの作成 $subject = "昇格操作が実行されました" $snsMessage = "以下の昇格操作が実行されました。`n`n" + "昇格先アカウント: $admin_account`n" + "イベント発生日時: $eventtime_jst`n" # Amazon SNSを使用して通知を送信 $messageId = (aws sns publish --topic-arn $TopicArn --subject $subject --message $snsMessage | ConvertFrom-Json).MessageId finally { # 環境変数をクリア Remove-Item Env:\AWS_ACCESS_KEY_ID -ErrorAction SilentlyContinue Remove-Item Env:\AWS_SECRET_ACCESS_KEY -ErrorAction SilentlyContinue Remove-Item Env:\AWS_DEFAULT_REGION -ErrorAction SilentlyContinue } }
トリガーの設定
トリガーにしたいイベントと、実行したいスクリプトが完成したので、最後にトリガーを設定します。
ここでは、Windowsのタスクスケジューラを用います。
「全般」タブにおいて、タスク名には任意の名前を設定します。一方、セキュリティオプション内の「タスクの実行時に使うユーザー アカウント」ではSYSTEMユーザーを指定します。
「トリガー」タブでは、トリガーを設定します。先程決定したイベントをトリガーとして設定します。
「タスクの開始」を「イベント時」、「ログ」を「セキュリティ」、「ソース」を「Microsoft Windows security auditing.」、「イベントID」を「4648」とします。
次にトリガーが発火した後の操作を設定します。
「操作」タブから「操作」を「プログラムの開始」、「プログラム/スクリプト」を「PowerShell.exe」、「引数の追加」で「-NoProfile -ExecutionPolicy Bypass -File “ファイルパス”」と指定します。
動作確認
実際に昇格操作を実施してみます。すると…
しっかりメールで通知がされました!
終わりに
今回はWindowsの標準機能とAWSの機能を組み合わせて管理者権限への昇格操作を通知する仕組みをご紹介しました。
タスクスケジューラのトリガーでは、トリガーのきっかけとなったイベントのログIDなどを知ることができないため、どのログによって発火したのかをPowerShellのスクリプトで知ることができません。
そのため、今回は30秒以内の最新の昇格操作を取得し送信するという対処法を取っています。
AWSのEventBridge的な感覚で触っていた私にとっては、この点は少し不便な仕様だな…と思った次第です。
余談
CloudWatch Agentをインストールして、セキュリティログをCloudWatch Logsに出力してゴニョゴニョ…の方がセンスあるかも?とも思いました。