🐡

WorkSpacesの実行ログを取得したい(Run Command編)

2023/11/05に公開

はじめに

Amazon WorkspacesはAWSが提供する仮想VDIサービスです。管理コンソールでポチポチするだけで簡単にVDIを構築できる非常に便利なサービスです。
一方、デフォルトの設定ではVDI上で誰が何をやったのかをAWSコンソールで一括監視することができません。
今回はSSMのRun Command機能を使用してWorkspacesの実行ログをCloudWatchLogsで監視する方法を紹介します
実装後の注意点も紹介しています。

忙しい人向けのまとめ

  1. Workspacesを監視する為にはCloudWatch Logsエージェントをインストールする必要がある
  2. インストール方法はいくつかあるが、今回紹介するSSMのRun Command機能を利用した方法がオススメ。"AWS-ConfigureAWSPackage"と"AmazonCloudWatch-ManageAgent"を実行することで実現可能
  3. SSMエージェントやCloudWatch Logsエージェントが停止してしまった場合に備えて、自動実行する為の設定を入れておくと安全。
    Windowsのタスクスケジューラ及びSSMのメンテナンスウィンドウ機能を使用

Workspacesを監視する方法

AWSが公式ドキュメントとして紹介している監視方法としては主に以下の2つがあります

しかし、WorkSpacesにログインした作業者が具体的にどのような作業をしたのかはAWSコンソールで確認することができません。その為、WorkSpaces実行環境のそれぞれにCloudWatch LogsエージェントをインストールしてCloudWatch Logsにログを送信する設定を行う必要があります。エージェントのインストール方法は主に2つあります

前者のほうが設定がシンプルであるものの、 WorkSpacesにはIAMロールを付与できない という制約があるので専用のIAM ユーザを発行した上でクレデンシャルを発行する必要があります。企業によってはこの部分がノックアウトになることもあると思います。
そんな状況に出会ってしまった方向けに、今回は後者のSSMのRun Commandでインストールする 方法を紹介します

やってみる

WorkSpacesにSSMエージェントをインストールする

WorkSpacesにSSMエージェントをインストールします。
Serverworksさんが【AWS Systems Manager】WorkSpacesをマネージドインスタンスとして登録してみるで紹介している方法にならって実施します。
PowerShell実施時に発行されるManagedInstanceIDは後で使うのでメモしておきましょう

注意点は以下です

  • 上記ブログではハイブリッドアクティベーションの設定の"IAMロール"を"システムによって作成されたデフォルトのロール"としています。しかし今回はCloudWatch Logsへログを送付する必要がある為、独自のロールを作成する必要があります。AWSマネージドポリシーの "AmazonSSMManagedInstanceCore""CloudWatchAgentServerPolicy" をアタッチさせて下さい

  • SSMエージェントのインストールがうまくいかない場合はAWS公式ドキュメントのステップ 4: ハイブリッドおよびマルチクラウド環境に SSM Agent をインストールする (Windows)を参照してインストールしてみてください

  • PowerShellは管理者権限で実行したほうがよさそうです

CloudWatch定義ファイル用のSSMパラメータストアを作成する

後述するSSM Run CommandではCloudWatch Logsの定義ファイルをSSMパラメータストアから読み取る仕様になっています。
AWS公式ドキュメントのCloudWatch エージェント設定ファイルを手動で作成または編集するを参照して定義ファイルを作成し、パラメータストアに格納します。

今回は以下のような定義ファイルを作成しました

定義ファイルはこちら(折りたたんであります)
{
   "logs": {
   	"logs_collected": {
   		"windows_events": {
   			"collect_list": [
   				{
   					"event_format": "xml",
   					"event_levels": [
   						"VERBOSE",
   						"INFORMATION",
   						"WARNING",
   						"ERROR",
   						"CRITICAL"
   					],
   					"event_name": "Application",
   					"log_group_name": "WorkSpaces-UserN",
   					"log_stream_name": "Application",
   					"retention_in_days": -1
   				},
   				{
   					"event_format": "xml",
   					"event_levels": [
   						"VERBOSE",
   						"INFORMATION",
   						"WARNING",
   						"ERROR",
   						"CRITICAL"
   					],
   					"event_name": "Security",
   					"log_group_name": "WorkSpaces-UserN",
   					"log_stream_name": "Security",
   					"retention_in_days": -1
   				},
   				{
   					"event_format": "xml",
   					"event_levels": [
   						"VERBOSE",
   						"INFORMATION",
   						"WARNING",
   						"ERROR",
   						"CRITICAL"
   					],
   					"event_name": "System",
   					"log_group_name": "WorkSpaces-UserN",
   					"log_stream_name": "System",
   					"retention_in_days": -1
   				},
   				{
   					"event_format": "xml",
   					"event_levels": [
   						"VERBOSE",
   						"INFORMATION",
   						"WARNING",
   						"ERROR",
   						"CRITICAL"
   					],
   					"event_name": "Setup",
   					"log_group_name": "WorkSpaces-UserN",
   					"log_stream_name": "Setup",
   					"retention_in_days": -1
   				},
   				{
   					"event_format": "xml",
   					"event_levels": [
   						"VERBOSE",
   						"INFORMATION",
   						"WARNING",
   						"ERROR",
   						"CRITICAL"
   					],
   					"event_name": "FowardedEvents",
   					"log_group_name": "WorkSpaces-UserN",
   					"log_stream_name": "ForwardedEvents",
   					"retention_in_days": -1
   				},
   				{
   					"event_format": "xml",
   					"event_levels": [
   						"VERBOSE",
   						"INFORMATION",
   						"WARNING",
   						"ERROR",
   						"CRITICAL"
   					],
   					"event_name": "Microsoft-Windows-TerminalServices-RDPClient/Operational",
   					"log_group_name": "WorkSpaces-UserN",
   					"log_stream_name": "Microsoft-Windows-TerminalServices-RDPClient/Operational",
   					"retention_in_days": -1
   				}
   			]
   		}
   	}
   },
   "metrics": {
   	"aggregation_dimensions": [
   		[
   			"InstanceId"
   		]
   	],
   	"append_dimensions": {
   		"AutoScalingGroupName": "${aws:AutoScalingGroupName}",
   		"ImageId": "${aws:ImageId}",
   		"InstanceId": "${aws:InstanceId}",
   		"InstanceType": "${aws:InstanceType}"
   	},
   	"metrics_collected": {
   		"LogicalDisk": {
   			"measurement": [
   				"% Free Space"
   			],
   			"metrics_collection_interval": 1,
   			"resources": [
   				"*"
   			]
   		},
   		"Memory": {
   			"measurement": [
   				"% Committed Bytes In Use"
   			],
   			"metrics_collection_interval": 1
   		},
   		"Paging File": {
   			"measurement": [
   				"% Usage"
   			],
   			"metrics_collection_interval": 1,
   			"resources": [
   				"*"
   			]
   		},
   		"PhysicalDisk": {
   			"measurement": [
   				"% Disk Time",
   				"Disk Write Bytes/sec",
   				"Disk Read Bytes/sec",
   				"Disk Writes/sec",
   				"Disk Reads/sec"
   			],
   			"metrics_collection_interval": 1,
   			"resources": [
   				"*"
   			]
   		},
   		"Processor": {
   			"measurement": [
   				"% User Time",
   				"% Idle Time",
   				"% Interrupt Time"
   			],
   			"metrics_collection_interval": 1,
   			"resources": [
   				"*"
   			]
   		},
   		"TCPv4": {
   			"measurement": [
   				"Connections Established"
   			],
   			"metrics_collection_interval": 1
   		},
   		"TCPv6": {
   			"measurement": [
   				"Connections Established"
   			],
   			"metrics_collection_interval": 1
   		}
   	}
   }
}

ちなみに"Microsoft-Windows-TerminalServices-RDPClient/Operational"はWorkSpacesから別のVDIにアクセスしたときの履歴を確認する為のログを格納しているようです。
(参考:RDP (Remote Desktop Protocol))

Run Commandを使用してCloudWatch Logsエージェントをインストールする

AWS公式ドキュメントのCloudWatch エージェントパッケージをダウンロードするを参照してCloudWatch Logsエージェントをインストールします
※上記のドキュメントはEC2にインストールしていますが、WorkSpacesに対しても問題なく実施が可能です

ターゲットにはこちらで取得したManagedInstanceIDを選択します

Run Commandを使用してCloudWatch Logsを起動する

AWS公式ドキュメントのSystems Manager Run Command を使用して CloudWatch エージェントを起動するを参照してCloudWatch Logsエージェントをインストールします。SSMパラメータストア名にはこちらで作成したパラメータストアの名称を入力します

結果の確認

CloudWatch上にログが格納されていることがわかると思います

SSMエージェントの自動起動設定を入れる

稀ですが、WorkSpaceにインストールしたSSMエージェントが停止してしまうことがあります。そうなると、Run Commandの実行やハイブリッドアクティベーションの各種機能が使用できなくなってしまいます。そうならない為にもSSMエージェントを定期的に起動する設定を入れておくことをお勧めします。
【Windows 10対応】タスクスケジューラで定期的な作業を自動化するの記事を参考にSSMエージェントを定期的に起動する設定を行います。
実行するコマンドはAWS公式ドキュメントのSSM Agent ステータスの確認とエージェントの起動を参照し、以下のように入力します。

Program/Script: %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
Add Arguments: -c "Start-Service AmazonSSMAgent"

CloudWatch Logsエージェントの自動起動設定を入れる

SSMエージェントと同様にCloudWatch Logsエージェントも自動で停止してしまうことがあります。こちらは、SSMのメンテナンスウィンドウ機能を使用して自動実行することをお勧めします。
今回は30分に一回CloudWach Logsエージェントを起動する設定を行います

メンテナンスウィンドウの設定画面にてウィンドウ名と実行スケジュールを入力します。
※画像はあくまで一例です

次にターゲットを登録します。ターゲットタブでターゲットの登録を選択し、[こちら](#Run Commandを使用してcloudwatch-logsエージェントをインストールする)と同様にターゲットを登録します

メンテナンスウィンドウ作成後、タスクタブから Run Commandタスクの登録 を選択します
パラメータは[こちら](#Run Commandを使用してcloudwatch-logsエージェントをインストールする)と同様にSSMのパラメータストア名称などを入力します。

"IAMサービスロール"の項目にはAWS公式ドキュメントのSetting up Maintenance Windows及びUse the console to configure permissions for maintenance windowsを参照し、以下のポリシーを持ったロールを事前に作成し、設定します。

ロールの信頼関係はこちら(折りたたんであります)
{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Sid": "",
           "Effect": "Allow",
           "Principal": {
               "Service": "cloudformation.amazonaws.com"
           },
           "Action": "sts:AssumeRole"
       }
   ]
}
IAMポリシーはこちら(折りたたんであります)
{
   "Version": "2012-10-17",
   "Statement": [
       {
           "Effect": "Allow",
           "Action": [
               "ssm:SendCommand",
               "ssm:CancelCommand",
               "ssm:ListCommands",
               "ssm:ListCommandInvocations",
               "ssm:GetCommandInvocation",
               "ssm:GetAutomationExecution",
               "ssm:StartAutomationExecution",
               "ssm:ListTagsForResource",
               "ssm:GetParameters"
           ],
           "Resource": "*"
       },
       {
           "Effect": "Allow",
           "Action": [
               "states:DescribeExecution",
               "states:StartExecution"
           ],
           "Resource": [
               "arn:aws:states:*:*:execution:*:*",
               "arn:aws:states:*:*:stateMachine:*"
           ]
       },
       {
           "Effect": "Allow",
           "Action": [
               "lambda:InvokeFunction"
           ],
           "Resource": [
               "arn:aws:lambda:*:*:function:*"
           ]
       },
       {
           "Effect": "Allow",
           "Action": [
               "resource-groups:ListGroups",
               "resource-groups:ListGroupResources"
           ],
           "Resource": [
               "*"
           ]
       },
       {
           "Effect": "Allow",
           "Action": [
               "tag:GetResources"
           ],
           "Resource": [
               "*"
           ]
       },
       {
           "Effect": "Allow",
           "Action": "iam:PassRole",
           "Resource": "*",
           "Condition": {
               "StringEquals": {
                   "iam:PassedToService": [
                       "ssm.amazonaws.com"
                   ]
               }
           }
       }
   ]
}

これで定期的にログが配信されない、なんて事態になる可能性は大きく減ります。

おまけ

今回CloudWatch Logsエージェントを30分ごとに起動していますが、間の30分のログも問題なく取得できます。
AWSの公式ドキュメントのエージェントを停止させた場合、データ損失や重複が発生しますか。にも記載がある通り、停止した場所から再開してログ送付を行う為です。

最後に

今回はCloudWatch Logsを起動するまでの方法をご紹介しましたが、パッチマネージャやステートマネージャを使用してより細かい管理を管理コンソールやCLIで実行することもできます。
是非試してみてください!

Discussion