こんにちは、中川です。
Amazon Connect アドベントカレンダー 2022、3日目の記事です!
Amazon Connect アドベントカレンダー 2022はクラスメソッドとギークフィードさんの有志が募ってチャレンジしている企画になります。
今年の4月にAmazon Connectユーザーの作成やセキュリティプロファイルを更新したときの操作が、CloudTrailに出力されるようになるアップデートがありました。
アップデート以前はAmazon Connectインスタンスにログインすることでしか操作履歴を確認できず、出力する機能もなかったため、操作履歴を監査ログとして扱いたい場合に悩ましかったです。 本記事では監査ログとしてAmazon Connectユーザの操作履歴が求められるケースを想定して、Athenaでログを取得をしてみます。
やってみた
前提
ログの対象とするユーザ操作関連のAPIは以下とします。
- CreateUser
- DeleteUser
- UpdateUserIdentityInfo
- UpdateUserSecurityProfiles
- UpdateUserRoutingProfile
- UpdateUserPhoneConfig
- UpdateUserHierarchyStructure
- UpdateUserHierarchyGroupName
- UpdateUserHierarchy
また、事前にAthenaでは下記ドキュメントを参考にCloudTrailのテーブルを作成していることとします。
Creating the table for CloudTrail logs in Athena using partition projection
そのままログを取得してみる
まずはログのフォーマットをCloudTrail上から確認します。
以下はCreateUserの抜粋です。実行ユーザの情報は userIdentity.principalId
から取得できそうです。
CreateUserでどのユーザが作成されたかについては requestParameters.Username
から取得できそうです。
次に、DeleteUserやUpdateUserSecurityProfilesのログを確認してみます。
変更対象のユーザについては requestParameters.Username
から取得できそうです。
出力したい情報を確認できたので、クエリを投げてみます。
SELECT
eventtime,
userIdentity.principalId AS executionUser,
eventname,
json_extract_scalar(requestParameters, '$.Username') AS createdUser,
json_extract_scalar(requestParameters, '$.UserId') AS operatedUser,
eventid
FROM
"AwsDataCatalog"."connect"."cloudtrail"
WHERE
eventname in (
'CreateUser',
'DeleteUser',
'UpdateUserIdentityInfo',
'UpdateUserSecurityProfiles',
'UpdateUserRoutingProfile',
'UpdateUserPhoneConfig',
'UpdateUserHierarchyStructure',
'UpdateUserHierarchyGroupName',
'UpdateUserHierarchy'
)
AND region = 'ap-northeast-1'
AND date > '2022/11/01'
AND date <= '2022/12/02'
AND useragent = 'connect.amazonaws.com'
ログとしてほしい情報は取れておりますが、以下の点が気になります。
- 操作されたユーザ(operatedUser)がわかりにくい
- 作成されたユーザ(createdUser)のようにメールアドレスで取得できない
- 実行したユーザ(executionUser)がわかりにくい
- 文字列が長い
- 文字数制限によりメールアドレス部分が途中で切れており、正確に出力できてない
クエリを追加して、実行ユーザと操作されたユーザがメールアドレスで表示できることをゴールにしたいと思います。
ユーザ情報をS3にアップロードする
operatedUserやexecutionUserのメールアドレス前の文字列は、Amazon Connectインスタンスで内部的に使用されるUserIdです。 ListUsers APIを実行することで、Connectインスタンスのユーザ名(メールアドレス)とUserIdDを取得できます。
$ aws connect list-users --instance-id 498ac4af-220c-4a9c-8436-b9c85bXXXXXX
{
"UserSummaryList": [
{
"Id": "1c71831d-8980-43e9-a7c8-4f1aeae10609",
"Arn": "arn:aws:connect:ap-northeast-1:1234XXXXXXXX:instance/498ac4af-220c-4a9c-8436-b9c85bXXXXXX/agent/1c71831d-8980-43e9-a7c8-4f1aeae10609",
"Username": "admin1@classmethod.jp"
},
{
"Id": "51f98508-d413-4434-b890-513e15aa196e",
"Arn": "arn:aws:connect:ap-northeast-1:1234XXXXXXXX:instance/498ac4af-220c-4a9c-8436-b9c85bXXXXXX/agent/51f98508-d413-4434-b890-513e15aa196e",
"Username": "test.taro@classmethod.jp"
},
{
"Id": "fb9bd02f-5ea3-4dff-b8d8-61475afe7af6",
"Arn": "arn:aws:connect:ap-northeast-1:1234XXXXXXXX:instance/498ac4af-220c-4a9c-8436-b9c85bXXXXXX/agent/fb9bd02f-5ea3-4dff-b8d8-61475afe7af6",
"Username": "admin2@classmethod.jp"
}
]
}
これをAthenaで結合できるようにしたいため、ListUsersの結果をS3にアップロードする処理をStepFunctionsで作ります。
作成したステートマシンは以下になります。ListUsersを実行し、UserSummaryListのユーザ配列ごとにjsonファイルを分割してS3にPutしています。分割して保存することによって、Connectユーザが削除されたあとにステートマシンを繰り返し実行しても、ユーザ情報をS3に残すことができます。
{
"Comment": "A description of my state machine",
"StartAt": "ListUsers",
"States": {
"ListUsers": {
"Type": "Task",
"Parameters": {
"InstanceId": "498ac4af-220c-4a9c-8436-b9c85bXXXXXX"
},
"Resource": "arn:aws:states:::aws-sdk:connect:listUsers",
"Next": "Map",
"ResultPath": "$"
},
"Map": {
"Type": "Map",
"InputPath": "$.UserSummaryList",
"ItemProcessor": {
"ProcessorConfig": {
"Mode": "INLINE"
},
"StartAt": "PutObject",
"States": {
"PutObject": {
"Type": "Task",
"End": true,
"InputPath": "$",
"Parameters": {
"Body.$": "$",
"Bucket": "connect-user-1234XXXXXXXX",
"Key.$": "$.Id"
},
"Resource": "arn:aws:states:::aws-sdk:s3:putObject"
}
}
},
"End": true
}
}
}
Athenaでクエリを投げ、ユーザー情報を取得できるか確認します。
テーブルを作成し、SELECTを実行すると以下のようにユーザ情報を取得できました。
CREATE EXTERNAL TABLE IF NOT EXISTS connect_users (
Arn string,
Id string,
Username string
) ROW FORMAT SERDE 'org.openx.data.jsonserde.JsonSerDe'
LOCATION 's3://connect-user-1234XXXXXXXX/'
ユーザ管理ログを取得する
準備ができましたので、テーブルを結合してユーザ管理ログを取得してみます。
WITH
user_data AS (
SELECT *
FROM
"AwsDataCatalog"."connect"."connect_users"
),
log_data AS (
SELECT
eventtime,
substring(userIdentity.principalId, 23, 36) AS executeuserid,
eventname,
json_extract_scalar(requestParameters, '$.Username') AS createdUser,
json_extract_scalar(requestParameters, '$.UserId') AS operatedUser,
eventId
FROM
"AwsDataCatalog"."connect"."cloudtrail"
WHERE
eventname in ('CreateUser',
'DeleteUser',
'UpdateUserIdentityInfo',
'UpdateUserSecurityProfiles',
'UpdateUserRoutingProfile',
'UpdateUserPhoneConfig',
'UpdateUserHierarchyStructure',
'UpdateUserHierarchyGroupName',
'UpdateUserHierarchy')
AND region = 'ap-northeast-1'
AND date > '2022/11/01'
AND date <= '2022/12/02'
AND useragent = 'connect.amazonaws.com'
)
SELECT
log_data.eventtime AS EventTime,
J1.username AS ExecuteUser,
log_data.eventname AS EventName,
log_data.username AS CreatedUser,
J2.username AS OperatedUser,
log_data.eventId AS EventId
FROM
log_data
LEFT JOIN user_data AS J1 ON log_data.executeuserid = J1.id
LEFT JOIN user_data AS J2 ON log_data.objectid = J2.id
実行ユーザ、操作されたユーザをメールアドレスで表示できることを確認できました!
さいごに
Amazon Connect のユーザ管理のログをAthenaで出力してみました。
そのまま出力した場合はConnect内部ユーザIDで出力されるため、ユーザ情報の付け合せが必要となり使い勝手がよろしくありませんでした。
ユーザ情報の一覧を取得するAPIを組み合わせることによって、ログとして扱いやすくなります。
今回はStepFunctionsを1回だけ実行しましたが、実際の環境で使う場合はスケジューリングやAthenaの実行と合わせて行うなどご検討ください。