Skip to content

ToDo and Design of refactored branch

masahiko edited this page Feb 13, 2017 · 26 revisions

Design

できているもの、できていないもの関係なく設計のメモ。

議論中の新フォーマットはこちら

サポート対象バージョン

  • 9.6系

設定ファイル

設定ファイルはpostgresql.confとは別に用意する。これは、悪意を持ったユーザが故意にログ出力設定を変更し、証跡を消すことを防ぐため。 pgaudit.config_fileに指定されたファイルをパースして、メモリに展開する。 pgaudit_scan.lで定義。

対応するフォーマットは以下の通り。

[output] # outputセクション
logger = 'serverlog'
  :
[options] # optionsセクション
role = 'audit_role'
log_parameter = on # comment 2
log_catalog = off
  :
[rule] # ruleセクション1
format = 'AUDIT SESSION-1: %p ...'
class = 'MISC'
database = 'postgres, hoge_db'
  :
[rule] # ruleセクション2
format = 'AUDIT SESSION-2 : %p ...'
class = 'READ, WRITE,FUNCTION'
database = 'postgres, hoge_db'
timestamp = '00:00:00 - 12:00:00, 13:00:00-14:00:00'
remote_port = '5432, 6543'
  :

以下、詳細な設計。

  • 設定ファイルはoptions, output, ruleの3つのセクションを持つことが可能。
    • output, optionsは設定ファイル内で一つだけ指定可能
    • ruleは複数指定可能
  • 各設定値は、
    • 論理値を入れるパラメータ(log_parameterなど)→on, off, true, false, 1, 0で設定
      • シングルクォーテーションなしで記載
      • 例) log_parameter = on
    • その他→シングルクォーテーションで囲む(例、'5432, 5555'とか'postgres, hoge_database')
      • 数値であってもカンマ区切りで複数指定する可能性があるため、シングルクォーテーションで囲む。
      • 例) remote_port = '5432'
    • timestampについてはHH:MM:SS-HH:MM:SSを一塊として、カンマ区切りで指定する。
      • 例) timestamp = '00:00:00 - 12:00:00, 13:00:00-14:00:00'
    • 間のスペースはすべて無視される。  - 日付のフォーマットに合わなかったら、パースエラーとする。
    • 大文字、小文字の区別はしない。
      • ただし、formatについては大文字、小文字を意識して出力する。
  • 演算子は、
    • = → ルールに一致するものをログに出す
    • != → ルールに一致しないものをログに出す
      • 例) object_id != 'public.hoge_table'
  • #で始まる行はコメントとして扱う。
    • コメントは行の途中でも可能。

設定ファイルのメモリ展開

設定値関連の関数はconfig.c、config.hに定義。

  • outputoptionsセクションについては、既存のpgauditの変数に格納する。(例えば、[options]のroleはauditRoleに格納する)
  • ruleセクションについては複数設定可能なので、ruleConigsにリスト形式でルール情報を格納。(詳細は後述)

rule section

  • ルールはフィールドによって4つのタイプに分類する。また、ルールのタイプ毎にルールに当てはまるかどうかを判定する関数がある。(apply_XXX_rule()関数)
    • AUDIT_RULE_TYPE_STRING
      • 文字列を格納するフィールド。databaseとかobject_idとか
      • apply_string_rule()で判定する
    • AUDIT_RULE_TYPE_TIMESTAMP
      • タイムスタンプを格納するフィールド。timestampのみ
      • apply_timestamp_rule()で判定する。
    • AUDIT_RULE_TYPE_BITMAP
      • 文字列で格納するけど、内部ではBitmapで持つもの。classobject_type
      • apply_bitmap_rule()で判定する
  • apply_XXX_rule()を抽象化する関数として、apply_one_rule()がある。
    • 第一引数に判定対象の値へのポインタ、第二引数にルールの構造体を入れる。
  • 各ルールは、auditRule構造体で持っていて、配列でまとまっている。
    • 各ルールの添字は、AUDIT_RULE_XXXと一致する。
/* 各ルールは「ルール名、設定値、=か!=か、設定値の個数、ルールのタイプ」の順で格納 */
struct AuditRule rules_template[] =
{
    {"timestamp", NULL, false, 0, AUDIT_RULE_TYPE_TIMESTAMP},
    {"database", NULL, false, 0, AUDIT_RULE_TYPE_STRING},
    {"audit_role", NULL, false, 0, AUDIT_RULE_TYPE_STRING},
    {"class", NULL, false, 0, AUDIT_RULE_TYPE_BITMAP},
    {"object_type", NULL, false, 0, AUDIT_RULE_TYPE_BITMAP},
    {"object_id", NULL, false, 0, AUDIT_RULE_TYPE_STRING},
    {"application_name", NULL, false, 0, AUDIT_RULE_TYPE_STRING},
    {"remote_host", NULL, false, 0, AUDIT_RULE_TYPE_STRING}
};

イベントのログ出力(メイン処理)

処理のメインとなる関数(hook等)をpgaudit.c、pgaudit.hに定義(個人的にはここも用途別にファイルを分けたい。。)

ログ出力の設計は以下のとおり。

  • 出力内部関数
    • SESSIONログはlog_audit_eventまたは、emit_log_hookで出力する。
      • log_audit_event()関数
        • 基本的にすべてのイベントはlog_audit_eventを通り、
          1. apply_all_rules()がtrue かつ
          2. stackItem->granted == false  のイベントがSESSIONログとして出力される。
    • emit_log_hook()関数
      • emit_log_hookですべてのログを引っ掛けて、目的のログかどうかを文字列一致で判定して、出力する。(advancedでやっている方法踏襲)
      • なにか他にいい方法があれば採用したい。
    • pgaudit内でのログ出力はEREPORT(ereport相当)、ELOG(elog相当)を使用する  - これは、emit_log_hookの無限ループにならないようにするために用意した関数。
  • 監査ログ以外のサーバログの扱い
    • 設定ファイルでlog_levelが設定できるが、これは監査ログのみを対象とする。通常の運用で出すpgauditのログには適用されないようにする。
  • 監査ログの内容
    • 監査に必要な固定の内容のデータを出力。(いつ、誰が、どこから、何をした、など)
    • 出力形式は、optionsセクションでcsv、ssv(スペース区切り)、key-value(auditdの出力形式にあわせて)から選択可能。
      • csvの例) ap_srv,10000,SELECT,TABLE,SELECT * FROM rel;
      • key-vauleの例) host=ap_srv port=10000 command=SELECT kind=TABLE sql=SELECT * FROM rel;
      • ssvの例) ap_srv 10000 SELECT TABLE "SELECT * FROM rel;"

ルールの判定

基本方針は、

  • 「ルールが未定儀=出力」 。これはオリジナルpgauditと仕様が異なる所なので注意。(例えば、ruleにclassがない場合はすべてのclassを出力することになる)

  • ルールセクション自体の記述がない場合は、ルールがないということになるので監査ログ出力はしない。

  • 指定されているルールが全部一致した場合に監査ログを出力する。

    • 複数のルールにマッチしたイベントは、マッチした分だけのログが出力される  - なので一つのSQLで複数の監査ログが出力される可能性もある。
  • 例1 (ruleセクションのみ→全ログを出力)

$ cat audit.conf
:
[rule]
$
  • 例2(ruleセクションにルールの記載あり→databaseとclassに一致した監査ログを出力)
$ cat audit.conf
:
[rule]
database = 'hogedb'
class = 'READ, WRITE'

syslog対応

基本的にはadvancedブランチにあるやり方を踏襲すれば良いはず。

Done

  • 全般
    • 設定ファイルの対応
    • ルール判定のインフラ(apply_ruleまわり)
    • 接続、切断、レプリケーションコマンド等もログに出すようなインフラの整備(emit_log_hook)
    • 設定ファイルのコメント対応
  • ルール対応
    • database
    • object_id
    • class
  • その他
    • ドキュメント更新

ToDo(★は優先度高)

  • 全般
    • エラーコード整備、エラー対応(ereportやelogの出力)★
    • syslog対応★
      • 設定値のパース部分だけはできてる。
    • 複数の形式で監査ログを出力できるようにする。csv、ssv、key-valueなど。最低でもcsvはサポートする。
    • 監査ログがどのルールによって出力されているかわからないので、「適用されたルール番号」を出しても良いかも。
  • ルール対応(各種ルールを判定できるようにする。優先度高順)
    • audit_role★
      • ユーザ名の一致で判別する機能は追加済み。以下の項目は改善項目として検討する。
      • 指定されたロールに所属するユーザが監査ログの出力対象になる。ユーザ名ではなく、ロールを指定するところが大切。
      • ロールを使って監査ユーザを判別できるようにする。優先度高。
    • command_tag
      • SELECT, INSERT, ALTERのレベルでフィルタをする。
      • 便利だけど、class(READ, WRITEでフィルタする)とかぶっている部分もあるので、優先度低。
  • その他
    • テスト★
      • 機能を追加するときは対応するテストと一緒にPRしてください。
    • advancedブランチのregression testを取り込む。
    • スタンバイサーバ上でも問題なく動くかを確認。
      • できればテストケースとして入れたい。