はじめに
皆さん、EC2インスタンスの操作はどのように行ってますか?
2018年9月に登場したSystemsManagerの1つの機能であるSessionManagerを使い
踏み台サーバを用意せず、EC2を操作しているインフラ管理者の方も増えてきたのではないでしょうか。
【参考】
・ AWS Systems Manager Session Manager
本投稿の内容
2020年11月17日にアップデートがありました。
ストリーミングで出力されるログをAmazon Elasticsearch Service(以降、Amazon ES)に取り込み
Kibanaで可視化してみました!
お客様は、セッションが終了するまで待つのではなく、セッション期間中、セッションログをCloudWatchに継続的にストリーミングできるようになりました。ログはJSONメッセージとして構造化され、セッションを開始するユーザー、インスタンスIDとセッションID、およびセッションからのコマンドと出力を識別します。セッションの期間中、構造化ログを継続的に受信して処理する機能により、ユーザーアクティビティの可視性が向上します。構造化ログを使用すると、セッションの開始や特定のコマンドの使用などの条件を簡単に検索して、セッションアクティビティの分析とトラブルシューティングに役立てることができます。
このアップデートでかなりログの完全性や信頼性が上がっているはず!!
【参考】
・ Amazon CloudWatch Logs を使用してセッションデータをストリーミングする
利用環境
項目 | 内容 |
---|---|
logstash (OSS版) | 7.9.3 |
Java (Corretto) | 11.0.10+9-LTS |
OS(EC2) | Amazon Linux2 (t3.small) |
AMI ID | ami-0e999cbd62129e3b1 |
Elasticsearch | 7.9 (latest) |
Region | us-west-2 |
※投稿時点における最新版を採用しています。 |
【構成図】
・ CloudWatch Logsにリアルタイム出力されたログをLogstashがTailしています。
【補足】
・ Amazon ESへのログ格納にはElastic社のETLツールであるLogstashを利用します。
・ Amazon ESはOSS版のため、LogstashもOSS版とし、バージョンも合わせています。
・ Amazon ESはパブリックアクセスとし、IPアドレス制御でセキュリティを確保しています。
【参考】
・ Logstashとは
実施内容
- IAM Roleの作成
- ロググループの作成
- セッションアクティビティログの出力
- SSM Agentバージョンアップ
- Amazon ESのドメイン作成
- Logstashの構築
- スキーマ定義とデータ取り込み
- ダッシュボードの作成
1. IAM Roleの作成
- EC2として構築するLogstashに割り当てるIAM Roleを作成します。
-
RoleForLogstash
を作成し、以下の2つのIAM Policyを割り当てます。
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:Describe*",
"logs:Get*",
"logs:List*",
"logs:StartQuery",
"logs:StopQuery",
"logs:TestMetricFilter",
"logs:FilterLogEvents"
],
"Effect": "Allow",
"Resource": "*"
}
]
}
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:DescribeAssociation",
"ssm:GetDeployablePatchSnapshotForInstance",
"ssm:GetDocument",
"ssm:DescribeDocument",
"ssm:GetManifest",
"ssm:GetParameters",
"ssm:ListAssociations",
"ssm:ListInstanceAssociations",
"ssm:PutInventory",
"ssm:PutComplianceItems",
"ssm:PutConfigurePackageResult",
"ssm:UpdateAssociationStatus",
"ssm:UpdateInstanceAssociationStatus",
"ssm:UpdateInstanceInformation"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2messages:AcknowledgeMessage",
"ec2messages:DeleteMessage",
"ec2messages:FailMessage",
"ec2messages:GetEndpoint",
"ec2messages:GetMessages",
"ec2messages:SendReply"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"cloudwatch:PutMetricData"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstanceStatus"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ds:CreateComputer",
"ds:DescribeDirectories"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams",
"logs:PutLogEvents"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"s3:GetBucketLocation",
"s3:PutObject",
"s3:GetObject",
"s3:GetEncryptionConfiguration",
"s3:AbortMultipartUpload",
"s3:ListMultipartUploadParts",
"s3:ListBucket",
"s3:ListBucketMultipartUploads"
],
"Resource": "*"
}
]
}
【補足】
・ 1つ目はLogstashがCloudWatch Logsのログを取得するための権限です。
・ 2つ目はSessionManager経由でLogstashを操作したり、ログ出力するための権限です。
・ ロググループを限定する場合は、Resoureceを限定するポリシーを別途作成します。
2. ロググループの作成
-
CloudWatch > CloudWatch Logs > Log groups
でロググループの作成をおこないます。 - ロググループ名は好きな名前をつけましょう。(今回はSessionActivityLogsとしています)
【補足】
・ 保持期間はデフォルト無期限ですが、必要に応じて変更してください。
・ ログの暗号化が必要な場合は、KMS鍵オプションを利用してください。
3. セッションアクティビティログの出力
-
Systems Manager > Session Manager > 設定
で設定画面に移動します。 -
編集ボタンを押して、設定をおこないます。
-
CloudWatch logging
をEnableとします。 -
Choose your preferred logging option
を**Stream session logs(デフォルト)**とします。 -
最下部の保存ボタンを押して設定を保存します。
【補足】
・ ログを暗号化している場合は、Allow only encrypted CloudWatch log groupにチェックを入れてください。
4.SSM Agentバージョンアップ
The SSM Agent version installed on this instance doesn't support streaming logs to CloudWatch. Either update the SSM Agent to the latest version, or disable the streaming logs option in your preferences.
-
Systems Manager > Run Command
からバージョンをあげます。 -
最下部の実行ボタンを押してバージョンアップを開始します。(数分で完了します)
-
なんと、すぐにCloudWatch Logsのロググループに打ったコマンド単位でログが出力されています!!
-
CloudWatch Logsに出力されるセッションアクティビティログのフォーマットは以下のようになってました。
項目 | 値(サンプル) | 説明 |
---|---|---|
eventVersion | 1.0 | ログイベント形式のバージョン |
eventTime | 2021-02-13T13:23:56Z | イベントの発生日時(UTC) |
awsRegion | us-west-2 | EC2の存在するAWSリージョン |
target.id | i-0e111111111222xxx | 操作対象EC2のインスタンスID |
userIdentity.arn | arn:aws:iam::AWSアカウント:user/IAMユーザ | 操作しているユーザのARN |
runAsUser | ssm-user | EC2のOSへログインしたユーザ名 |
sessionId | hibino-0d95217a3276b8641 | SessionManagerのセッションID |
sessionData | "sh-4.2$ sudo su" | OSで実行したコマンドとその戻り値 |
- Amazon ESを使って、sessionDataを全文検索することでユーザ操作の監査がかなりの精度で出来そうですね!
5. Amazon ESのドメイン作成
- 下記内容でAmazon ESのドメインを作成します。
項目 | 値 |
---|---|
リージョン | us-west-2 |
デプロイタイプ | 開発およびテスト |
Elasticsearchのバージョン | 7.9 (latest) |
Elasticsearchのドメイン | test-es |
インスタンスタイプ | t3.small.elasticsearch |
ノードの数 | 1 |
データノードのストレージタイプ | EBS |
EBS ボリュームタイプ | 汎用(SSD) |
EBS ボリュームサイズ | 10 GiB |
自動スナップショットの開始時間 | 00:00 UTC (デフォルト) |
ネットワークアクセス | パブリックアクセス |
細かいアクセスコントロールを有効化 | 無効 |
KibanaのSAML認証 | 無効 |
Amazon Cognito認証を有効化 | 無効 |
ドメインアクセスポリシー | カスタムアクセスポリシー (IPv4アドレス) |
ドメインへのすべてのトラフィックにHTTPSを要求 | 有効 |
ノード間の暗号化 | 有効 |
保管時のデータの暗号化の有効化 | 有効 |
KMSマスターキー | (デフォルト) aws/es |
- アクセスポリシーに追加するIPは、Amazon ESにアクセスする自宅IPとLogstashのIPになります。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": "es:*",
"Resource": "arn:aws:es:us-west-2:<AWSアカウント>:domain/test-es/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": [
"<自宅IP>/32",
"<LogstasのEIP>/32"
]
}
}
}
]
}
6. Logstashの構築
- Logstashの構築手順は、Amazon Corretto 11で構築するLogstashになります。
- 下記のパイプライン構成ファイル(
/etc/logstash/conf.d/logstash.conf
)を作成します。
(このタイミングではLogstashのプロセスは起動しません)
$ sudo vi /etc/logstash/conf.d/logstash.conf
- 下記の内容を上記のパイプライン構成ファイルに記述します。
input {
## CloudWatch LogsのSessionActivityLogsのロググループから5秒間隔でログ取得
cloudwatch_logs {
log_group => [ "SessionActivityLogs" ]
region => "us-west-2"
interval => 5
}
}
filter {
### JSONパーサーによる解析
json {
source => "message"
}
### dateフィールドから@timestampを抽出
date {
match => [ "eventTime", "ISO8601" ]
timezone => "UTC"
target => "@timestamp"
}
### @timstampから日本時間を抽出
ruby {
code => "event.set('[@metadata][local_time]',event.get('[@timestamp]').time.localtime.strftime('%Y-%m-%d'))"
}
### document_idに利用する一意のIDを作成
fingerprint {
source => "message"
target => "[@metadata][fingerprint]"
method => "MURMUR3"
}
### フィールドの追加と削除
mutate {
### typeフィールドを追加
add_field => { "type" => "log-aws-ssm-sessionlog" }
### 不要なフィールドを削除
remove_field => [ "eventTime", "message" ]
}
}
output {
### 出力先のAmazonESのIndexを指定
elasticsearch {
hosts => [ "https://search-test-es-xxxxxxxxxxxxxxxxxxxxxx.us-west-2.es.amazonaws.com:443" ]
index => "%{type}-%{[@metadata][local_time]}"
document_id => "%{[@metadata][fingerprint]}"
ilm_enabled => false
}
}
【参考】
・ cloudwatch-logs input
・ json filter
・ date filter
・ ruby filter
・ fingerprint filter
・ mutate filter
・ elasticsearch output
7. スキーマ定義とデータ取り込み
-
Kibanaの初回アクセス時に下記の画面が表示されます。
-
Consoleからセッションアクティビティログ用のIndex Templateを追加します。
-
上記で張り付けたIndex Templateは以下の通りです。
PUT _template/log-aws-ssm-sessionlog
{
"index_patterns": ["log-aws-ssm-sessionlog-*"],
"settings": {
"number_of_shards": 1,
"number_of_replicas" : 1
},
"mappings": {
"properties": {
"@timestamp": {
"type": "date"
},
"@version" : {
"type" : "keyword"
},
"eventVersion" : {
"type" : "keyword"
},
"awsRegion" : {
"type" : "keyword"
},
"target.id" : {
"type" : "keyword"
},
"userIdentity.arn" : {
"type" : "keyword"
},
"runAsUser" : {
"type" : "keyword"
},
"sessionId" : {
"type" : "keyword"
},
"sessionData" : {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 8191
}
}
},
"type" : {
"type" : "keyword"
},
"tags" : {
"type" : "keyword"
},
"cloudwatch_logs" : {
"properties" : {
"event_id" : {
"type" : "keyword"
},
"ingestion_time" : {
"type" : "date"
},
"log_group" : {
"type" : "keyword"
},
"log_stream" : {
"type" : "keyword"
}
}
}
}
}
}
【補足】
・ sessionDataフィールドは全文検索することが想定されるためtext型
としています。
・ Kibanaで時系列データとして扱うための時刻フィールドは@timestamp
としています。
・ 他フィールドは完全一致検索やKibanaの可視化に利用するためkeyword型
としています。
- ここでLogstashを起動します。
$ sudo systemctl start logstash
$ sudo systemctl status logstash
● logstash.service - logstash
Loaded: loaded (/etc/systemd/system/logstash.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2021-02-13 14:54:43 UTC; 1s ago
Main PID: 32506 (java)
CGroup: /system.slice/logstash.service
└─32506 /bin/java -Xms1g -Xmx1g -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75 -XX:+UseCMSInitiatingOccupancyOnly -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djruby.compile.invok...
Feb 13 14:54:43 ip-172-31-12-56.us-west-2.compute.internal systemd[1]: Started logstash.
Feb 13 14:54:43 ip-172-31-12-56.us-west-2.compute.internal systemd[1]: Starting logstash...
Feb 13 14:54:43 ip-172-31-12-56.us-west-2.compute.internal logstash[32506]: OpenJDK 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a...re release.
Hint: Some lines were ellipsized, use -l to show in full.
-
GET _cat/indices/log-aws-ssm-sessionlog*
を実施し、インデックスが生成されていることを確認します。
-
[Stack Management] > [Index Patterns]でCreate index patternをクリックします。
-
[Discover]を開き、Index Patternに
log-aws-ssm-sessionlog-*
を指定します。 -
取り込んだログは以下のような感じです。
{
"_index": "log-aws-ssm-sessionlog-2021-02-13",
"_type": "_doc",
"_id": "2962024441",
"_version": 1,
"_score": null,
"_source": {
"runAsUser": "ssm-user",
"cloudwatch_logs": {
"ingestion_time": "2021-02-13T15:15:50.046Z",
"log_group": "SessionActivityLogs",
"log_stream": "hibino-07ffa10afb273b008",
"event_id": "35976216682055508680804654953801519308351663213472448512"
},
"eventVersion": "1.0",
"@version": "1",
"type": "log-aws-ssm-sessionlog",
"sessionData": [
"\u001b]0;root@ip-172-31-12-56:/usr/bin\u0007[root@ip-172-31-12-56 bin]# ",
"\u001b]0;root@ip-172-31-12-56:/usr/bin\u0007[root@ip-172-31-12-56 bin]# "
],
"target": {
"id": "i-0e111111111222xxx"
},
"sessionId": "hibino-07ffa10afb273b008",
"awsRegion": "us-west-2",
"@timestamp": "2021-02-13T15:15:50.000Z",
"userIdentity": {
"arn": "arn:aws:iam::123456789012:user/hibino"
}
},
"fields": {
"@timestamp": [
"2021-02-13T15:15:50.000Z"
],
"cloudwatch_logs.ingestion_time": [
"2021-02-13T15:15:50.046Z"
]
},
"sort": [
1613229350000
]
}
8. ダッシュボードの作成
-
まず、[Discover]で下記のフィールドをAddをします。
-
awsRegion
、runAsUser
、sessionId
、target.id
、userIdentity.arn
がSelected fieldsにあることを確認します。 -
上記と同様に
sessionId
、target.id
、userIdentity.arn
で表グラフを作成し、別名で保存します。 -
同様に
runAsUser
、sessionId
、target.id
、userIdentity.arn
で表グラフを作成し、別名で保存します。 -
適当な名前をつけて、ダッシュボードを保存します。
まとめ
とてつもなく長い投稿になってしまいましたが、いかがでしたでしょうか?
私がKibanaでよく利用するグラフは、棒グラフ、表グラフ、円グラフです。
それ以外は、ログ監査ではあまり利用していないのが実態です。
このダッシュボードの作りだと、各フィールドの値でフィルタリング(+または-)することが出来ます。
フィルタリングすることで再検索がかかり、見つけたいデータや情報を絞り込んでいくことが可能です。
これは使える!!と思われた方、ぜひLGTMを^^v