ApsaraDB RDS for PostgreSQLでは、イベントトリガーを使用して、DDLごみ箱、ファイアウォール、増分同期などの機能を実装できます。 これにより、メンテナンスコストを削減し、データセキュリティを保護できます。
前提条件
RDSインスタンスはPostgreSQL 10、11、または12を実行し、標準または拡張SSDを搭載しています。背景情報
イベントトリガーに基づいてDDLごみ箱とファイアウォールポリシーを作成し、データベースのセキュリティを確保できます。
- DROP TABLE、DROP INDEX、DROP DATABASEなどの危険な操作を防ぎます。
- テーブルが誤って削除された場合、ごみ箱からデータを取得します。
pg_get_ddl_commandとpg_get_ddl_dropの2つのイベントトリガーを使用して、DDL文を収集してdts_audit.dts_tb_ddl_commandテーブルに保存できます。 イベントトリガーは、pg_func_ddl_command() 関数を使用して実装されます。 dts_audit.dts_tb_ddl_commandテーブルの構造は次のとおりです。
列 | タイプ | 照合順序 | Nullable | デフォルト | ストレージ | ターゲット統計 | 説明
----------------- ----------------------------- ---------- ----------- -------------------- ---------------------------------------------------------
イベント | テキスト | | | | | 拡张 | |
タグ | text | | | | 拡張 | | コマンドタグ
classid | oid | | | | plain | | オブジェクトが属していたカタログのOID
objid | oid | | | | plain | | カタログ内のオブジェクトのOID
objsubid | integer | | | | plain | | オブジェクトサブid (例: 列の属性番号)
object_type | text | | | | 拡張 | | オブジェクトのタイプ
schema_name | text | | | | 拡張 | | オブジェクトが属するスキーマの名前 (存在する場合) 。 引用は適用されません。
object_identity | text | | | | 拡張 | | オブジェクトIDのテキストレンダリング、スキーマ修飾。
is_extension | boolean | | | | plain | | コマンドが拡張スクリプトの一部である場合はTrue
クエリ | テキスト | | | | 拡張 | | sql text
username | text | | | | CURRENT_USER | 拡張 | |
datname | テキスト | | | current_database() | 拡張 | |
client_addr | inet | | | inet_client_addr() | main | |
crt_time | タイムゾーンなしのタイムスタンプ | | | now() | plain | |
必要なCREATEステートメントは次のとおりです。
dts_auditが存在しない場合はスキーマを作成します。CREATE TABLE IF NOT EXISTS dts_audit.dts_tb_ddl_command (イベントテキスト、タグテキスト, classid oid, objid oid, objsubid int,
object_typeテキスト、schema_nameテキスト、object_identityテキスト、is_extension bool、クエリテキスト、username text default current_user、datname text default current_database() 、client_addr inetデフォルトinet_client_addr() 、crt_time timestamp default now()
);
次のセクションでは、DDLごみ箱、ファイアウォール、増分同期を実装する方法の例を示します。 必要に応じてコードを変更できます。
DDLのごみ箱
- 次のステートメントを実行して、必要なテーブル、関数、およびトリガーを作成します。
/* external/rds_ddl_pulication/rds_ddl_pulication -- 1.0.sql * / -- スキーマの作成 dts_auditが存在しない場合はスキーマを作成します。-ddlレコードのテーブルを作成する CREATE TABLE IF NOT EXISTS dts_audit.dts_tb_ddl_command (イベントテキスト、タグテキスト, classid oid, objid oid, objsubid int, object_typeテキスト、schema_nameテキスト、object_identityテキスト、is_extension bool、クエリテキスト、username text default current_user、datname text default current_database() 、client_addr inet default inet_client_addr() 、crt_time timestamp default now() ); -- イベントトリガーの関数を作成する createまたはreplace関数dts_audit.dts_func_ddl_command() は $$としてevent_triggerを返します v1テキストを宣言する。is_superuser bool = false; rレコード; 始める -スーパーユーザーからのddlコマンドを記録しません pg_catalog.pg_roles uからu.rolsuperをis_superuserに選択します。ここで、u.rolname = SESSION_USER; is_superuserの場合、 戻る; end if; pid=pg_backend_pid() であるpg_stat_activityからv1にクエリを選択します。 -- RAISE NOTICE 'ddl event :%、コマンド: % '、tg_event、tg_tag; -- NB: ddl_command_endはdropステートメントの詳細を収集できないため、sql_dropを使用します。 TG_EVENT='ddl_command_end 'の場合、 SELECT * into r FROM pg_event_trigger_ddl_commands(); r.classid > 0の場合、 insert into dts_audit.dts_tb_ddl_command(event, tag, classid, objid, objsubid, object_type, schema_name, object_identity, is_extension, query) 値 (TG_EVENT、TG_TAG、r.classid、r.objid、r.objsubid、r.object_type、r.schema_name、r.object_identity、r.in_extension、v1); end if; end if; TG_EVENT='sql_drop' の場合、 -繰り返し収集を避けるために、「ALTER TABLE」と「ALTER FOREIGN TABLE」をフィルタリングしました もしTG_TAG! ='ALTER TABLE' とTG_TAG! =「ALTER FOREIGN TABLE」の場合 SELECT * into r FROM pg_event_trigger_dropped_objects(); insert into dts_audit.dts_tb_ddl_command(event, tag, classid, objid, objsubid, object_type, schema_name, object_identity, is_extension, query) 値 (TG_EVENT、TG_TAG、r.classid、r.objid、r.objsubid、r.object_type、r.schema_name、r.object_identity、'f' 、v1); end if; 終了if; 終了; $$ language plpgsql strict; -- ddl_command_endイベントトリガー イベントトリガーを作成するpg_get_ddl_command on ddl_command EXECUTE PROCEDURE dts_audit.dts_func_ddl_command(); -- pg_get_ddl_dropイベントトリガー イベントトリガーを作成するpg_get_ddl_drop on sql_drop EXECUTE PROCEDURE dts_audit.dts_func_ddl_command(); -すべてのユーザーに権限を付与する SCHEMA dts_auditからパブリックへの使用を承認します。選択を許可し、テーブルに挿入して公開します。
説明 上記のステートメントを実行すると、DDLステートメントがdts_audit.dts_tb_ddl_commandテーブルに記録されます。 - DDL文を実行して、それがdts_audit.dts_tb_ddl_commandテーブルに記録されているかどうかをテストします。
テーブルtb_test(id int) を作成します。select * from dts_audit.dts_tb_ddl_command;
DDLファイアウォール
必要に応じてイベントトリガーを作成し、ddl_command_startイベントを使用して特定のDDL文の実行をブロックできます。
- トリガー関数を作成します。
関数の作成または置き換えabort1() RETURNS event_trigger LANGUAGE plpgsql AS $$ 開始 current_user = 'test1' の場合、 RAISE EXCEPTION 'event :%, コマンド: % ', tg_event, tg_tag; end if; エンド; $$;
- テーブルを作成または削除するDDLステートメントをブロックするトリガーを作成します。
タグIN ('CREATE TABLE', 'DROP TABLE') がプロシージャabort1() を実行したときにddl_command_startにイベントトリガーbを作成します。
- ユーザーtest1としてRDSインスタンスにログインし、テーブルを作成します。説明 DDLステートメントがブロックされています。
増分同期
パブリケーション側では、実行されたDDL文はdts_audit.dts_tb_ddl_commandテーブルに格納されます。 パブリケーション側からサブスクリプション側にレコードを同期できます。
- パブリケーション側でパブリケーションを作成します。
テーブル専用の出版物my_ddl_publicationを作成します。
- サブスクリプション側で同じテーブルを作成します。dts_auditが存在しない場合は
スキーマを作成します。CREATE TABLE IF NOT EXISTS dts_audit.dts_tb_ddl_command (イベントテキスト、タグテキスト, classid oid, objid oid, objsubid int, object_typeテキスト、schema_nameテキスト、object_identityテキスト、is_extension bool、クエリテキスト、ユーザー名テキスト、datnameテキスト、client_addr inet、crt_time timestamp );
- サブスクリプション側でサブスクリプションを作成します。
サブスクリプションの作成my_ddl_subscriptin CONNECTION 'host=*** port=*** user=*** password=*** dbname=**'PUBLICATION my_ddl_publication;
説明 RDSインスタンスのwal_levelパラメーターがlogicalに設定されていることを確認します。 ApsaraDB for RDSコンソールの [パラメーター] ページでパラメーター値を変更し、インスタンスを再起動して変更を有効にすることができます。 詳細については、「論理サブスクリプション機能の使用」をご参照ください。例:
CREATE SUBSCRIPTION my_ddl_subscriptin CONNECTION 'host=pgm-bpxxxxx.pg.rds.aliyuncs.comポート=1433 user=test1 password=xxxxx dbname=testdb1' PUBLICATION my_ddl_publication;
- DDL文の増分同期を実行するために、サブスクリプション側でdts_audit.dts_tb_ddl_commandテーブルのトリガーを作成します。