こんにちは、Aireです。
本記事では、EC2インスタンスを停止(シャットダウン)、再起動または終了(削除)するときに、ログ(ログ以外も可能)をS3に自動で保存する方法を紹介します。
本方法では、インスタンス内にログの自動保存用スクリプト一式を事前に仕込んで置くことで、OSの停止をトリガーにスクリプトを実行するようにしています。
前提条件
ログの自動保存用スクリプト一式を準備する前に、以下の前提条件に問題がないか確認してください。
- [必須]インスタンスにAWS CLIがインストールされていること…AWS CLIコマンドを使用してファイルをS3にアップロードします。
- [必須]インスタンスからS3にアクセスできること
- アクセス経路…VPC上にInternet GatewayやVPCエンドポイントなど、インスタンスからS3にアクセスできる環境を用意します。
- アクセス権限…S3へのアクセス権限を含むIAMロールをインスタンスにアタッチするか、または、AWS CLIのアクセスキー情報をインスタンス内にファイルとして保存します。セキュリティの観点から前者を推奨します。
- [任意]インスタンスのメタデータ(インスタンスID)にアクセスできること…本記事では、S3にアップロードするファイル名にインスタンスIDを含めています。含めない場合は本条件は省略可能です。
- インスタンスの
アクセス可能なメタデータのバージョン
がV1およびV2
であること…インスタンスIDなどのメタデータは、インスタンス内のメタデータエンドポイントにアクセスすることで取得できます。通常インスタンスを作成すると、アクセス可能なメタデータのバージョン
はV2のみ
となりますが、インスタンスIDのメタデータバージョンはV1であるため、インスタンスIDを利用したい場合は、インスタンスの作成時にV1およびV2
を選択するか、作成後に設定変更を行います。変更方法は公式ドキュメント(既存インスタンスのインスタンスメタデータオプションの変更)を参照してください。
- インスタンスの
Linuxインスタンスの場合
ログの自動保存用スクリプト一式の準備
本記事で準備するスクリプトは以下です。これらのファイルをOS上の任意の場所に格納してください。
- ログ保存スクリプト
- インスタンスの停止時に、ログ保存スクリプトを実行するためinit.dスクリプト
ログ保存スクリプト
以下のスクリプトは、システムログである”/var/log/messages”と”/var/log/secure”に日時情報とインスタンスIDを付与してS3へのアップロードを行います。本スクリプトのパスは任意です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
#!/bin/sh TARGET_FILE=("/var/log/messages" "/var/log/secure") # コピーするシステムログを記載 TODAY=`date +%Y%m%d_%H%M%S` # 現在の日時を取得 INSTANCE_ID=`curl http://169.254.169.254/latest/meta-data/instance-id` # インスタンス情報を取得 IP_ADDRESS=`curl http://169.254.169.254/latest/meta-data/local-ipv4` # インスタンス情報を取得 WORKING_DIR=/tmp/working_dir # 作業フォルダのパスを指定 mkdir -p $WORKING_DIR 2>/dev/null # 作業フォルダを作成 S3_BUCKET=samplebucket # S3バケット名を指定 S3_FOLDER=samplefolder # S3フォルダ名を指定 # AWSのアクセスキーを指定 (S3へのアクセス権限を含むIAM Roleをインスタンスにアタッチしない場合) AWS_SETTING=/root/.aws/credentials export AWS_CONFIG_FILE=$AWS_SETTING # システムログを作業フォルダにコピー echo ${TARGET_FILE[@]} | while read FILE_PATH do cp -f ${FILE_PATH} $WORKING_DIR/ done # ファイルを圧縮 for i in `find $WORKING_DIR -maxdepth 1 -type f | egrep -v gz` do gzip -c $i > $i"_shutdown_"$IP_ADDRESS"_"$INSTANCE_ID"_"${TODAY}.gz rm -f $i done # S3にアップロード aws s3 cp $WORKING_DIR s3://$S3_BUCKET/$S3_FOLDER/$TODAY --exclude "*" --include "*.gz" --recursive # 作業フォルダを削除 rm -rf $WORKING_DIR |
インスタンスの停止時にログ保存スクリプトを実行するためのinit.dスクリプト
以下のスクリプトは、OSの停止または再起動時にログ保存スクリプトを実行します。ログ保存スクリプトのパス情報は適宜修正してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#!/bin/bash # chkconfig: 345 99 01 SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin . /etc/init.d/functions # サービス起動時の処理 start() { touch /var/lock/subsys/cp_log_to_s3 } # サービス停止時の処理 stop() { rm -f /var/lock/subsys/cp_log_to_s3 sh /usr/local/bin/cp_log_to_s3.sh } # サービス再起動時の処理 restart() { stop start } case "$1" in start) start ;; stop) stop ;; restart) restart ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit 0 |
ログの自動保存サービスの登録と起動
以下のコマンドを実行し、cp_log_to_s3
サービスの登録と起動を行います。
1 2 3 4 5 |
$ chkconfig --add cp_log_to_s3 $ chmod +x /etc/init.d/cp_log_to_s3 $ service cp_log_to_s3 start Reloading systemd: [ OK ] Starting cp_log_to_s3 (via systemctl): [ OK ] |
動作確認テスト
以下のコマンドを実行しcp_log_to_s3
サービスを停止するか、インスタンス(OS)を停止または再起動し、ログ保存の動作確認を行います。
1 2 |
$ service cp_log_to_s3 stop Stopping cp_log_to_s3 (via systemctl): [ OK ] |
指定したS3フォルダの下に日付フォルダ(YYYYMMDD_hhmmss)が作成され、その中にログファイル(messages_shutdown_<IP address>_i-xxxxxxxxxxxxxxxxx_YYYYMMDD_hhmmss.gz、secure_shutdown_<IP address>_i-xxxxxxxxxxxxxxxxx_YYYYMMDD_hhmmss.gz)が保存されていれば成功です。
Windowsインスタンスの場合
ログの自動保存用スクリプト一式の準備
以下のスクリプトファイルを準備します。
- ログ保存スクリプト
ログ保存スクリプト
以下のPowerShellスクリプトは、WindowsイベントログであるSystemログとSecurityログに日時情報とインスタンスIDを付与してS3へのアップロードを行います。本スクリプトのパスは任意です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
$targetFile = @('system', 'security') # コピーするイベントログを記載 $today = Get-Date -Format "yyyyMMdd_HHmmss" # 現在の日時を取得 $instanceID = Invoke-RestMethod -Uri "http://169.254.169.254/latest/meta-data/instance-id" # インスタンス情報を取得 $ipAddress = Invoke-RestMethod -Uri "http://169.254.169.254/latest/meta-data/local-ipv4" # IPアドレスを取得 $workingDir = "C:\Program Files\WorkingDir" # 作業フォルダのパスを指定 New-Item -ItemType Directory -Path $workingDir -Force | Out-Null # 作業フォルダを作成 $s3Bucket = "samplebucket" # S3バケット名を指定 $s3Folder = "samplefolder" # S3フォルダ名を指定 # AWSのアクセスキーを指定 (S3へのアクセス権限を含むIAM Roleをインスタンスにアタッチしない場合) $awsSetting = "$env:USERPROFILE\.aws\credentials" $env:AWS_CONFIG_FILE = $awsSetting # イベントログを作業フォルダにエクスポート foreach ($fileName in $targetFile) { $filePath = $workingDir + "\" + $fileName + ".evtx" wevtutil export-log $fileName $filePath } # ファイルを圧縮 Get-ChildItem $workingDir | Where-Object {!$_.PSIsContainer -and $_.Extension -ne ".zip"} | ForEach-Object { $gzipFileName = $_.FullName + "_shutdown_" + $ipAddress + "_" + $instanceID + "_" + $today + ".zip" Compress-Archive -Path $_.FullName -DestinationPath $gzipFileName -Force Remove-Item $_.FullName -Force } # S3にアップロード aws s3 cp $workingDir s3://$s3Bucket/$s3Folder/$today --exclude "*" --include "*.zip" --recursive # 作業フォルダを削除 Remove-Item $workingDir -Force -Recurse |
ローカルグループポリシーにログ保存スクリプトを追加(GUI操作の場合)
ローカルグループポリシーエディターを開き、インスタンスの停止時に実行したいスクリプトを設定します。
- [User Configuration]-[Windows Settings]-[Scripts (Logon/Logoff)]に移動し、[Logoff]の[Properties]を開きます。
- [PowerShell Scripts]タブを開き、[Add]ボタンをクリックします。
- [Browse]ボタンをクリックします。
- 既定のパス(
C:\Windows\System32\GroupPolicy\User\Scripts\Logoff\
)が表示されるので、ここにログ保存スクリプトを格納・選択し、[Open]をクリックします。
- [OK]ボタンをクリックし、[Properties]画面を閉じます。
- コマンドプロンプトまたはPowerShellを開き、
gpupdate
コマンドを実行します。
1 2 3 4 5 |
$ gpupdate Updating policy... Computer Policy update has completed successfully. User Policy update has completed successfully. |
ローカルグループポリシーにログ保存スクリプトを追加(CLI操作の場合)
PowerShellを開き、インスタンスの停止時に実行したいスクリプトを設定します。
- ログ保存スクリプトを格納するフォルダを作成します。ここでは
C:\Windows\System32\GroupPolicy\User\Scripts\Logoff\
を作成します。
1 2 |
$ $gpoPath = "C:\Windows\System32\GroupPolicy" $ New-Item (Join-Path $gpoPath "User\Scripts\Logoff") -ItemType Directory |
C:\Windows\System32\GroupPolicy\gpt.ini
に以下の内容を記載します。gpt.ini
はグループポリシーテンプレート(GPT)全体の設定ファイルです。ローカルグループポリシーエディター(GUI操作)でスクリプトを指定する場合は、本ファイルに設定が自動で反映されます。
1 2 3 |
[General] gPCUserExtensionNames=[{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}] Version=65536 |
項目 | 説明 | 値 |
---|---|---|
gPCUserExtensionNames | User Configuration(ユーザーの構成)でポリシーが設定されているクライアント側拡張(CSE)のリスト。 gPCUserExtensionNames=[{CSEのGUID}{サーバ側拡張のGUID}] | [{42B5FAAE-6536-11D2-AE5A-0000F87571E3}{40B66650-4972-11D1-A7CA-0000F87571E3}] |
Version | グループポリシーオブジェクト(GPO)のバージョン情報。[ユーザーの構成のバージョン(4桁の16進数)]+[コンピュータの構成のバージョン(4桁の16進数)]で構成された8桁の16進数を、10進数に変換した値。今回のようにユーザー構成の情報のみを新規に設定した場合、ユーザーの構成のバージョン(0001)とコンピュータの構成のバージョン(0000)により65536(= 00010000)が算出されます。 | 65536 |
C:\Windows\System32\GroupPolicy\User\Scripts\Logoff\psscripts.ini
に以下の内容を記載します。psscripts.ini
は実行するスクリプトの情報を記載します。ローカルグループポリシーエディター(GUI操作)でスクリプトを指定する場合は、本ファイルに設定が自動で反映されます。
1 2 3 |
[Logoff] 0CmdLine=cp_log_to_s3.ps1 0Parameters= |
項目 | 説明 | 値 |
---|---|---|
nCmdLine | 実行するスクリプト。複数のスクリプトを実行する場合は、先頭の値を増やしていきます。(0CmdLine、1CmdLine、…) | cp_log_to_s3.ps1 |
nParameters | スクリプトのオプション。実行するスクリプトに合わせて、先頭の値を指定します。(0Parameters、1Parameters、…) | なし(今回使用するスクリプトにはオプションなし) |
- コマンドプロンプトまたはPowerShellを開き、
gpupdate
コマンドを実行します。
1 2 3 4 5 |
$ gpupdate Updating policy... Computer Policy update has completed successfully. User Policy update has completed successfully. |
動作確認テスト
インスタンス(OS)を停止または再起動し、ログ保存の動作確認を行います。
指定したS3フォルダの下に日付フォルダ(YYYYMMDD_hhmmss)が作成され、その中にログファイル(system.evtx_shutdown_<IP address>_i-xxxxxxxxxxxxxxxxx_YYYYMMDD_hhmmss.zip、security.evtx_shutdown_<IP address>_i-xxxxxxxxxxxxxxxxx_YYYYMMDD_hhmmss.zip)が保存されていれば成功です。