👓

Aurora DBに接続したユーザー情報をSlackに通知する

に公開

序論

皆さんは本番環境のデータベースに誰が入っているかしっかり記録していますか?
当たり前のことですが、本番環境のデータベースに誰が接続しているのかわからない状態というのはあまりよろしくありません。
誰がいつデータベースにアクセスしたか記録することは、監査上重要です。
今回はKiro[1]の力を借りてデータベースにアクセスがあったらSlackへ通知するAWS SAM[2]サーバーレスアプリケーションを構築してみましたのでご紹介いたします。

対象読者

  • Aurora MySQL/PostgreSQLを使っている
  • DBへの接続情報を記録する必要がある
  • AWS SAMの基本的な知識がある
  • Goの知識がある(LambdaはGoで実装しています)

構成概要

仕組みは単純でユーザーがデータベースに接続したらログをCloudWatch Logsへ出力させ、サブスクリプションフィルターでLambdaにログを転送します。
ログを受け取ったLambdaはログの中身をSlack通知へ適するように整形し、接続ログを転送しています。

Aurora ログ出力手順

Aurora側でCloudWatch Logsへログを出力させる場合、パラメータグループで出力するログの種類について事前にフィルタリングすることが望ましいです。ログ量が増えるとCloudWatch Logsのコストやログを確認する運用の負荷が増してしまうので適切にログを出力するようにします。

パラメータグループの設定

Auroraならパラメータグループの設定から行なえますが、SQLからでも設定変更できます。

-- MySQL の場合
SET GLOBAL general_log = 'ON';
SET GLOBAL log_output = 'FILE';

-- PostgreSQL の場合
SET log_connections = on;

Aurora構築時にログエクスポート設定を有効化すれば、CloudWatch Logsに以下のようなログが出力されます。

# MySQL
2025-09-23T09:34:39.173138Z	  176 Connect	test28@10.0.140.132 on mysql using TCP/IP

# PostgreSQL
2025-09-23 10:49:18 UTC:10.0.136.99(48800):yuta@postgres:[4914]:LOG:  connection authorized: user=yuta database=postgres application_name=psql SSL enabled (protocol=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384, bits=256)

このログメッセージをそのままSlackに送信すると視認性が悪いので、AWS SAMでログを整形するサーバーレスアプリケーションを実装しました。

AWS SAM実装

テンプレートの全体像は以下のリポジトリにMySQL、PostgreSQLそれぞれ分けて作ってあります。
https://github.com/Yuhta28/go-lambda/tree/main

  • MySQL

https://github.com/Yuhta28/go-lambda/blob/main/mysql-connect-audit/mysql-connect-audit/main.go

  • PostgreSQL

https://github.com/Yuhta28/go-lambda/blob/main/postgresql-connect-audit/postgresql-connect-audit/main.go

単にコードを載せて終わりですと味気ないので実装で工夫した点についていくつか説明いたします。

システムユーザーの除外

Aurora MySQL/PostgreSQLはシステムユーザーの定期的な接続情報がCloudWatch Logsに記録され、そのログもSlackへ通知させてしまうと大量に通知され運用しづらくなります。

# MySQL
2025-09-23T11:12:31.939073Z	  665 Connect	rdsadmin@localhost on  using Socket

# PostgreSQL
2025-09-23 10:49:01 UTC:10.0.136.99(53898):[unknown]@[unknown]:[4897]:LOG:  connection received: host=10.0.136.99 port=53898

これらのログをCloudWatch Logsへ出力させないようにするのはAWSの仕様上難しそう[3]でしたので、アプリケーション側で回避できるようにシステムユーザーを除外して不要なログを通知させないようにしました。

  • MySQL

https://github.com/Yuhta28/go-lambda/blob/main/mysql-connect-audit/mysql-connect-audit/main.go#L94-L100

  • PostgreSQL

https://github.com/Yuhta28/go-lambda/blob/main/postgresql-connect-audit/postgresql-connect-audit/main.go#L92-L100

JST変換

CloudWatch Logsに出力されたログのタイムスタンプはUTC表記になっており、データベースのタイムゾーンを変更してもJSTのタイムスタンプで出力できません。


CloudWatch LogsのタイムスタンプはJSTでもログのタイムスタンプはUTC

ログを受け取ってLambdaのなかでタイムスタンプをUTCからJST表記に変更することで時刻の認識違いを防ぐようにしてます。

  • MySQL

https://github.com/Yuhta28/go-lambda/blob/main/mysql-connect-audit/mysql-connect-audit/main.go#L115-L116

  • PostgreSQL

https://github.com/Yuhta28/go-lambda/blob/main/postgresql-connect-audit/postgresql-connect-audit/main.go#L117-L119

デプロイ

SAMテンプレートの内容はLambdaと付随するIAMロールの作成くらいで基本的にGitHubにあげている内容をそのまま流用できます。
https://github.com/Yuhta28/go-lambda/blob/main/postgresql-connect-audit/template.yaml

一通りコードを書き終えたらビルドしてデプロイしていきます。

# ビルド
$ make build
sam build
Starting Build use cache
Valid cache found, copying previously built resources for following functions (MysqlConnectAuditFunction)

Build Succeeded

Built Artifacts  : .aws-sam\build
Built Template   : .aws-sam\build\template.yaml

Commands you can use next
=========================
[*] Validate SAM template: sam validate
[*] Invoke Function: sam local invoke
[*] Test Function in the Cloud: sam sync --stack-name {{stack-name}} --watch
[*] Deploy: sam deploy --guided

# デプロイ

$ make deploy
sam deploy --guided

Configuring SAM deploy
======================

        Looking for config file [samconfig.toml] :  Found
        Reading default arguments  :  Success

        Setting default arguments for 'sam deploy'
        =========================================
        Stack Name [mysql-connect-audit]:
        AWS Region [ap-northeast-1]:
        Parameter SlackWebhookUrl: # SlackのIncoming Webhookで生成したWebhook URLを入力する
        Parameter AuroraClusterIdentifier [handson-db-mysql]: # Auroraクラスター名を入力する
        Parameter CloudWatchLogGroupName [/aws/rds/cluster/handson-db-mysql/general]: # Cloudwatch Logグループ名を入力する
        #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
        Confirm changes before deploy [Y/n]:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

CloudFormation outputs from deployed stack


Successfully created/updated stack - mysql-connect-audit in ap-northeast-1

Slack通知確認

実際にAuroraへログインしてSlackに通知されるか確認します。MySQLにユーザーが接続したらCloudwatch Logに接続情報が記録されます。


appdbにtest28ユーザーが接続した

このログを先のサーバーレスアプリケーションでSlackへ以下のように通知させてみました。

PostgreSQLも同様に通知できました。

所感

Auroraへのユーザー接続情報をSlackへ通知することで誰がいつデータベースへアクセスしたか監査できるサーバーレスアプリケーションを実装してみました。
ログをCloudwatch Logに出してもリアルタイムですぐに確認することは難しいのでSlackへ通知できる仕組みを実装することで統制がとれるようになりますので、参考になりましたら幸いです。

参考文献

https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraMySQL.Integrating.CloudWatch.html
https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/AuroraPostgreSQL.CloudWatch.html

脚注
  1. https://kiro.dev/ ↩︎

  2. https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/what-is-sam.html ↩︎

  3. https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/Appendix.MySQL.Options.AuditPlugin.html#Appendix.MySQL.Options.AuditPlugin.Options ↩︎

Discussion