
pgaudit v19beta2
PostgreSQL監査拡張機能
pgAudit
オープンソース PostgreSQL 監査ログ記録
はじめに
PostgreSQL Audit Extension (pgAudit) は、標準の PostgreSQL ログ機能を介して、詳細なセッションおよびオブジェクトの監査ログを提供します。
pgAudit の目標は、政府、金融、ISO 認証などの要件を満たすために必要な監査ログを生成する機能を PostgreSQL ユーザーに提供することです。
監査とは、通常、独立した機関による個人または組織のアカウントの公式な検査です。pgAudit によって収集された情報は、監査証跡または監査ログと呼ばれます。このドキュメントでは「監査ログ」という用語を使用します。
なぜ pgAudit なのか?
基本的なステートメントログは、log_statement = all を設定することで標準のログ機能によって提供できます。これは監視やその他の用途には許容されますが、通常監査に必要なレベルの詳細を提供しません。データベースに対して実行されたすべての操作のリストがあるだけでは不十分です。監査人が関心を持つ特定のステートメントを見つけることも可能でなければなりません。標準のログ機能はユーザーが要求した内容を示しますが、pgAudit はデータベースが要求を満たしている間に実際に何が起こったかの詳細に焦点を当てます。
たとえば、監査人は特定のテーブルが文書化されたメンテナンスウィンドウ内に作成されたことを確認したい場合があります。これは grep で簡単にできるように思えますが、次のような (意図的に難読化された) 例に直面したらどうでしょうか:
DO $$
BEGIN
EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;
標準ログでは次のように出力されます:
LOG: statement: DO $$
BEGIN
EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;
テーブルが動的に作成される場合、目的のテーブルを見つけるにはコードに関する知識が必要になる可能性があることがわかります。テーブル名だけで検索できれば理想的ですが、そうではありません。ここで pgAudit が活躍します。同じ入力に対して、ログに次の出力を生成します:
AUDIT: SESSION,33,1,FUNCTION,DO,,,"DO $$
BEGIN
EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;"
AUDIT: SESSION,33,2,DDL,CREATE TABLE,TABLE,public.important_table,CREATE TABLE important_table (id INT)
DO ブロックがログに記録されるだけでなく、サブステートメント 2 には CREATE TABLE の全文がステートメントタイプ、オブジェクトタイプ、完全修飾名とともに含まれているため、検索が容易です。
SELECT および DML ステートメントをログに記録する場合、pgAudit はステートメント内で参照される各リレーションに対して個別のエントリをログに記録するように設定できます。特定のテーブルに触れるすべてのステートメントを見つけるために解析は必要ありません。実際、目標はステートメントテキストが主に詳細なフォレンジックのために提供され、監査には必須ではないことです。
使用上の考慮事項
設定によっては、pgAudit が膨大な量のログを生成する可能性があります。環境で何を監査ログに記録する必要があるかを正確に判断し、過剰なログを避けるように注意してください。
たとえば、OLAP 環境で作業する場合、大規模なファクトテーブルへの挿入を監査ログに記録することは賢明ではないでしょう。ログファイルのサイズは、挿入の実際のデータサイズの何倍にもなる可能性があります。ログファイルはテキストとして表現されるためです。ログは通常 OS とともに保存されるため、ディスク容量がすぐに枯渇する可能性があります。特定のテーブルに監査ログを制限できない場合は、テスト中にパフォーマンスへの影響を評価し、ログボリュームに十分なスペースを割り当ててください。これは OLTP 環境にも当てはまる可能性があります。挿入ボリュームがそれほど高くなくても、監査ログのパフォーマンスへの影響がレイテンシに顕著に影響を与える可能性があります。
SELECT および DML ステートメントで監査ログに記録されるリレーションの数を制限するには、オブジェクト監査ログ (「オブジェクト監査」を参照) の使用を検討してください。オブジェクト監査ログを使用すると、ログに記録するリレーションを選択できるため、全体的なログ量を削減できます。ただし、新しいリレーションが追加された場合は、オブジェクト監査ログに明示的に追加する必要があります。指定されたテーブルをログから除外し、それ以外をすべて含めるプログラムによる解決策が、この場合には適切な選択肢かもしれません。
PostgreSQL バージョン互換性
pgAudit は PostgreSQL 14 以降をサポートしています。
各 PostgreSQL リリースで導入される新機能をサポートするために、pgAudit は PostgreSQL のメジャーバージョンごとに個別のブランチ (現在は PostgreSQL 14 - 19) を維持しており、PostgreSQL プロジェクトと同様の方法で保守されます。
バグ修正以外には、安定版ブランチに対する新たな開発は許可されません。新たな開発 (もしあれば) は、リリースされていない次の PostgreSQL メジャーバージョンに限定されます。
pgAudit のバージョンは、PostgreSQL のメジャーバージョンと次のように対応します:
-
pgAudit v19.X は PostgreSQL 19 をサポートすることを目的としています。
-
pgAudit v18.X は PostgreSQL 18 をサポートすることを目的としています。
-
pgAudit v17.X は PostgreSQL 17 をサポートすることを目的としています。
-
pgAudit v16.X は PostgreSQL 16 をサポートすることを目的としています。
-
pgAudit v1.7.X は PostgreSQL 15 をサポートすることを目的としています。
-
pgAudit v1.6.X は PostgreSQL 14 をサポートすることを目的としています。
コンパイルとインストール
pgAudit は、開発パッケージがインストールされた PostgreSQL に対して PGXS を使用してコンパイルできます。以下の手順は、ほとんどの Unix 系オペレーティングシステムで動作するはずです。
pgAudit 拡張機能をクローンします:
git clone https://github.com/pgaudit/pgaudit.git
pgAudit ディレクトリに移動します:
cd pgaudit
REL_19_STABLE ブランチをチェックアウトします (リリースされていない PostgreSQL バージョンでは安定版ブランチが存在しない場合があることに注意):
git checkout REL_19_STABLE
pgAudit をビルドしてインストールします:
make install USE_PGXS=1 PG_CONFIG=/usr/pgsql-19/bin/pg_config
テストと開発に関する手順は test にあります。
設定
設定はスーパーユーザーのみが変更できます。通常のユーザーが自分の設定を変更できるようにすると、監査ログの目的が損なわれます。
設定は、グローバル (postgresql.conf または ALTER SYSTEM ... SET を使用)、データベースレベル (ALTER DATABASE ... SET を使用)、またはロールレベル (ALTER ROLE ... SET を使用) で指定できます。設定は通常のロール継承によって継承されず、SET ROLE はユーザーの pgAudit 設定を変更しないことに注意してください。これはロールシステムの制限であり、pgAudit に固有のものではありません。
pgAudit 拡張機能は shared_preload_libraries にロードする必要があります。そうしないと、ロード時にエラーが発生し、監査ログは記録されません。
さらに、pgaudit.log を設定する前に CREATE EXTENSION pgaudit を呼び出して、適切な pgaudit 機能を確保する必要があります。この拡張機能はイベントトリガーをインストールし、DDL に追加の監査機能を提供します。pgAudit は拡張機能がインストールされていなくても動作しますが、DDL ステートメントにはオブジェクトタイプと名前に関する情報が含まれません。
pgaudit 拡張機能を削除して再作成する必要がある場合は、最初に pgaudit.log を設定解除する必要があります。そうしないとエラーが発生します。
pgaudit.log
セッション監査ログによってどのクラスのステートメントがログに記録されるかを指定します。指定可能な値は次のとおりです:
-
READ: ソースがリレーションまたはクエリである場合の
SELECTおよびCOPY。 -
WRITE: 宛先がリレーションである場合の
INSERT、UPDATE、DELETE、TRUNCATE、およびCOPY。 -
FUNCTION: 関数呼び出しおよび
DOブロック。 -
ROLE: ロールと権限に関するステートメント:
GRANT、REVOKE、CREATE/ALTER/DROP ROLE。 -
DDL:
ROLEクラスに含まれないすべてのDDL。 -
MISC: その他のコマンド。例:
DISCARD、FETCH、CHECKPOINT、VACUUM、SET。 -
MISC_SET: その他の
SETコマンド。例:SET ROLE。 -
ALL: 上記のすべてを含みます。
複数のクラスはカンマ区切りリストで指定でき、クラス名の前に - 記号を付けて除外できます (「セッション監査ログ」を参照)。
デフォルトは none です。
pgaudit.log_catalog
ステートメント内のすべてのリレーションが pg_catalog にある場合にセッションログを有効にするかどうかを指定します。この設定を無効にすると、psql や PgAdmin などのツールがカタログを頻繁にクエリすることによるログのノイズが減少します。
デフォルトは on です。
pgaudit.log_client
ログメッセージが psql などのクライアントプロセスから表示可能かどうかを指定します。この設定は通常は無効のままにすべきですが、デバッグやその他の目的には役立つ場合があります。
pgaudit.log_level は pgaudit.log_client が on の場合にのみ有効になることに注意してください。
デフォルトは off です。
pgaudit.log_level
ログエントリに使用されるログレベルを指定します (有効なレベルについては「メッセージ重大度レベル」を参照)。ただし、ERROR、FATAL、PANIC は許可されません。この設定はリグレッションテストに使用され、エンドユーザーがテストやその他の目的にも役立つ場合があります。
pgaudit.log_level は pgaudit.log_client が on の場合にのみ有効になることに注意してください。それ以外の場合はデフォルトが使用されます。
デフォルトは log です。
pgaudit.log_parameter
監査ログにステートメントとともに渡されたパラメータを含めるかどうかを指定します。パラメータが存在する場合、ステートメントテキストの後に CSV 形式で含まれます。
デフォルトは off です。
pgaudit.log_parameter_max_size
この設定値 (バイト単位) より長いパラメータ値はログに記録せず、代わりに <long param suppressed> に置き換えることを指定します。これはバイト単位で設定され、文字単位ではないため、テキストパラメータのエンコーディングにおけるマルチバイト文字は考慮されません。この設定は log_parameter が off の場合は効果がありません。この設定が 0 (デフォルト) の場合、長さに関係なくすべてのパラメータがログに記録されます。
デフォルトは 0 です。
pgaudit.log_relation
セッション監査ログが SELECT または DML ステートメントで参照される各リレーション (TABLE、VIEW など) に対して個別のログエントリを作成するかどうかを指定します。これはオブジェクト監査ログを使用せずに詳細なログを取るための便利なショートカットです。
デフォルトは off です。
pgaudit.log_rows
監査ログにステートメントによって取得または影響を受けた行数を含めるかどうかを指定します。有効にすると、行数フィールドがパラメータフィールドの後に含まれます。
デフォルトは off です。
pgaudit.log_statement
ログにステートメントテキストとパラメータ (有効な場合) を含めるかどうかを指定します。要件によっては、監査ログにこれが不要な場合もあり、ログの冗長性を低下させます。
デフォルトは on です。
pgaudit.log_statement_once
ログにステートメントテキストとパラメータを、ステートメント/サブステートメントの組み合わせの最初のログエントリのみに含めるか、すべてのエントリに含めるかを指定します。この設定を有効にすると、ログの冗長性は低下しますが、ログエントリを生成したステートメントを特定するのが難しくなる可能性があります。ただし、ステートメント/サブステートメントのペアとプロセス ID があれば、以前のエントリでログに記録されたステートメントテキストを特定するには十分なはずです。
デフォルトは off です。
pgaudit.role
オブジェクト監査ログに使用するマスターロールを指定します。マスターロールに権限を付与することで、複数の監査ロールを定義できます。これにより、複数のグループが監査ログのさまざまな側面を担当することが可能になります。
デフォルトはありません。
セッション監査ログ
セッション監査ログは、バックエンドでユーザーが実行したすべてのステートメントの詳細なログを提供します。
設定
セッションログは pgaudit.log 設定で有効になります。
すべての DML および DDL に対してセッションログを有効にし、DML ステートメント内のすべてのリレーションをログに記録します:
set pgaudit.log = 'write, ddl';
set pgaudit.log_relation = on;
MISC を除くすべてのコマンドに対してセッションログを有効にし、監査ログメッセージを NOTICE として出力します:
set pgaudit.log = 'all, -misc';
set pgaudit.log_level = notice;
例
この例では、セッション監査ログを使用して DDL および SELECT ステートメントをログに記録します。WRITE クラスが有効になっていないため、insert ステートメントはログに記録されないことに注意してください。
SQL:
set pgaudit.log = 'read, ddl';
create table account
(
id int,
name text,
password text,
description text
);
insert into account (id, name, password, description)
values (1, 'user1', 'HASH1', 'blah, blah');
select *
from account;
ログ出力:
AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.account,create table account
(
id int,
name text,
password text,
description text
);,<not logged>
AUDIT: SESSION,2,1,READ,SELECT,,,select *
from account,,<not logged>
オブジェクト監査ログ
オブジェクト監査ログは、特定のリレーションに影響を与えるステートメントをログに記録します。SELECT、INSERT、UPDATE、DELETE コマンドのみがサポートされています。TRUNCATE はオブジェクト監査ログに含まれません。
オブジェクト監査ログは、pgaudit.log = 'read, write' のより細かい代替として意図されています。そのため、これらを併用することは意味をなさないかもしれませんが、考えられるシナリオの1つとして、セッションログを使用して各ステートメントをキャプチャし、特定のリレーションに関するより詳細な情報を得るためにオブジェクトログを補足として使用することが挙げられます。
設定
オブジェクトレベルの監査ログは、ロールシステムを介して実装されます。pgaudit.role 設定は、監査ログに使用されるロールを定義します。監査ロールが実行されたコマンドに対する権限を持っているか、別のロールから権限を継承している場合、そのリレーション (TABLE、VIEW など) は監査ログに記録されます。これにより、任意のコンテキストで単一のマスターロールしかなくても、実質的に複数の監査ロールを持つことができます。
pgaudit.role を auditor に設定し、account テーブルに SELECT および DELETE 権限を付与します。これで account テーブルに対する SELECT または DELETE ステートメントがログに記録されるようになります:
set pgaudit.role = 'auditor';
grant select, delete
on public.account
to auditor;
例
この例では、オブジェクト監査ログを使用して、SELECT および DML ステートメントのログ記録に対する詳細なアプローチを示します。account テーブルのログ記録は列レベルの権限によって制御され、account_role_map テーブルのログ記録はテーブルレベルであることに注意してください。
SQL:
set pgaudit.role = 'auditor';
create table account
(
id int,
name text,
password text,
description text
);
grant select (password)
on public.account
to auditor;
select id, name
from account;
select password
from account;
grant update (name, password)
on public.account
to auditor;
update account
set description = 'yada, yada';
update account
set password = 'HASH2';
create table account_role_map
(
account_id int,
role_id int
);
grant select
on public.account_role_map
to auditor;
select account.password,
account_role_map.role_id
from account
inner join account_role_map
on account.id = account_role_map.account_id
ログ出力:
AUDIT: OBJECT,1,1,READ,SELECT,TABLE,public.account,select password
from account,<not logged>
AUDIT: OBJECT,2,1,WRITE,UPDATE,TABLE,public.account,update account
set password = 'HASH2',<not logged>
AUDIT: OBJECT,3,1,READ,SELECT,TABLE,public.account,select account.password,
account_role_map.role_id
from account
inner join account_role_map
on account.id = account_role_map.account_id,<not logged>
AUDIT: OBJECT,3,1,READ,SELECT,TABLE,public.account_role_map,select account.password,
account_role_map.role_id
from account
inner join account_role_map
on account.id = account_role_map.account_id,<not logged>
フォーマット
監査エントリは標準のログ機能に書き込まれ、カンマ区切り形式で次の列を含みます。出力は、各ログエントリのログラインプレフィックス部分を削除した場合にのみ、CSV 準拠の形式になります。
-
AUDIT_TYPE -
SESSIONまたはOBJECT。 -
STATEMENT_ID - このセッションの一意のステートメント ID。各ステートメント ID はバックエンド呼び出しを表します。一部のステートメントがログに記録されなくても、ステートメント ID は連続します。複数のリレーションがログに記録される場合、1 つのステートメント ID に複数のエントリが存在する可能性があります。
-
SUBSTATEMENT_ID - メインステートメント内の各サブステートメントの連続 ID。たとえば、クエリから関数を呼び出す場合など。一部のサブステートメントがログに記録されなくても、サブステートメント ID は連続します。複数のリレーションがログに記録される場合、1 つのサブステートメント ID に複数のエントリが存在する可能性があります。
-
CLASS - 例:
READ、ROLE(pgaudit.log を参照)。 -
COMMAND - 例:
ALTER TABLE、SELECT。 -
OBJECT_TYPE -
TABLE、INDEX、VIEWなど。SELECT、DMLおよびほとんどのDDLステートメントで利用可能です。 -
OBJECT_NAME - 完全修飾オブジェクト名 (例: public.account)。
SELECT、DMLおよびほとんどのDDLステートメントで利用可能です。 -
STATEMENT - バックエンドで実行されたステートメント。
-
PARAMETER -
pgaudit.log_parameterが設定されている場合、このフィールドには引用符で囲まれた CSV 形式のステートメントパラメータ、またはパラメータがない場合は<none>が含まれます。それ以外の場合、フィールドは<not logged>です。
log_line_prefix を使用して、監査ログの要件を満たすために必要なその他のフィールドを追加します。典型的なログラインプレフィックスは '%m %u %d [%p]: ' で、各監査ログに日付/時刻、ユーザー名、データベース名、プロセス ID を提供します。
注意事項
監査ログはベストエフォートであり、トランザクション的ではありません。pgAudit は標準の PostgreSQL ログ機能を介して監査エントリを書き込みますが、この機能は各エントリを生成したトランザクションと同期的にディスクにフラッシュするわけでも、書き込みエラーをセッションに伝播するわけでもありません。コミットされたトランザクションに対応する監査ログエントリが存在するという保証はありません。サーバーがクラッシュしたり電源が失われたり、ログの宛先が利用できなくなった場合 (ログボリュームがいっぱいになるなど)、トランザクションがコミットされた後で監査エントリが永続的に書き込まれる前に発生すると、それらのエントリは失われる可能性があります。逆に、ステートメントは実行時にログに記録されるため、トランザクションが後でロールバックしてもエントリが書き込まれる可能性があります。
オブジェクトの名前変更は、変更後の名前でログに記録されます。たとえば、テーブルの名前を変更すると、次の結果が生成されます:
ALTER TABLE test RENAME TO test2;
AUDIT: SESSION,36,1,DDL,ALTER TABLE,TABLE,public.test2,ALTER TABLE test RENAME TO test2,<not logged>
コマンドが複数回ログに記録される可能性があります。たとえば、作成時に主キーが指定されたテーブルが作成される場合、主キーのインデックスが個別にログに記録され、作成エントリの下にインデックスの別の監査ログが作成されます。ただし、複数のエントリは 1 つのステートメント ID 内に含まれます。
自動バキュームと自動分析はログに記録されません。
トランザクションがアボート状態になった後に実行されるステートメントは監査ログに記録されません。ただし、エラーの原因となったステートメントと、アボートされたトランザクション内で実行された後続のステートメントは、標準のログ機能によって ERROR としてログに記録されます。
pgAudit でスーパーユーザーを確実に監査することはできません。1 つの解決策は、スーパーユーザーアカウントへのアクセスを制限し、必要に応じて set_user 拡張機能を使用して権限を昇格させることです。
著者
PostgreSQL Audit Extension は、Simon Riggs、Abhijit Menon-Sen、Ian Barwick によって作成され、PostgreSQL コアへの拡張機能として提出された 2ndQuadrant の pgaudit プロジェクト に基づいています。追加の開発は Crunchy Data の David Steele によって行われました。