

Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.

# Dynamische Maskierung mit Aurora PostgreSQL verwenden
<a name="AuroraPostgreSQL.Security.DynamicMasking"></a>

Dynamische Datenmaskierung ist eine Sicherheitsfunktion, die sensible Daten in Aurora PostgreSQL-Datenbanken schützt, indem gesteuert wird, wie Daten Benutzern bei Abfragen angezeigt werden. Aurora implementiert es über die `pg_columnmask` Erweiterung. `pg_columnmask`bietet Datenschutz auf Spaltenebene, der die systemeigenen Sicherheits- und granularen Zugriffskontrollmechanismen von PostgreSQL auf Zeilenebene ergänzt.

Mit erstellen Sie Maskierungsrichtlinien`pg_columnmask`, die die Datentransparenz auf der Grundlage von Benutzerrollen festlegen. Wenn Benutzer Tabellen mit Maskierungsrichtlinien abfragen, wendet Aurora PostgreSQL zur Abfragezeit die entsprechende Maskierungsfunktion an, die auf der Rolle und der Richtliniengewichtung des Benutzers basiert. Die zugrunde liegenden Daten bleiben unverändert im Speicher.

`pg_columnmask`unterstützt die folgenden Funktionen:
+ **Integrierte und benutzerdefinierte Maskierungsfunktionen** — Verwenden Sie vorgefertigte Funktionen für gängige Muster wie E-Mail- und Textmaskierung oder erstellen Sie Ihre eigenen benutzerdefinierten Funktionen zum Schutz sensibler Daten (PII) mithilfe von SQL-basierten Maskierungsrichtlinien.
+ **Mehrere Maskierungsstrategien** — Verbergen Sie Informationen vollständig, ersetzen Sie Teilwerte durch Platzhalter oder definieren Sie benutzerdefinierte Maskierungsansätze.
+ **Priorisierung von Richtlinien** — Definieren Sie mehrere Richtlinien für eine einzelne Spalte. Verwenden Sie Gewichtungen, um zu bestimmen, welche Maskierungsrichtlinie verwendet werden soll, wenn mehrere Richtlinien für eine Spalte gelten. Aurora PostgreSQL wendet Richtlinien an, die auf Gewicht und Benutzerrollenzugehörigkeit basieren. 

`pg_columnmask`ist auf Aurora PostgreSQL Version 16.10 und höher und Version 17.6 und höher verfügbar. Es ist ohne zusätzliche Kosten verfügbar.

# Erste Schritte mit dynamischer Maskierung
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted"></a>

Um Daten dynamisch zu maskieren, installieren Sie die `pg_columnmask` Erweiterung in Ihrer Datenbank und erstellen Maskierungsrichtlinien für Ihre Tabellen. Der Einrichtungsprozess umfasst die Überprüfung der Voraussetzungen, die Installation der Erweiterung, die Rollenkonfiguration, die Erstellung von Richtlinien und die Überprüfung von Validierungstests.

## Installation und Konfiguration von Erweiterungen
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted.Installation"></a>

Stellen Sie mit dem RDS Console Query Editor oder einem PostgreSQL-Client wie psql mit rds\$1superuser (Masteruser) -Anmeldeinformationen eine Connect zu Ihrem Aurora PostgreSQL-Cluster her.

Führen Sie den Befehl zur Erstellung der Erweiterung aus, um die Funktionalität zu aktivieren: `pg_columnmask`

```
CREATE EXTENSION pg_columnmask;
```

Mit diesem Befehl wird die `pg_columnmask` Erweiterung installiert, die erforderlichen Katalogtabellen erstellt und die integrierten Maskierungsfunktionen registriert. Die Installation der Erweiterung ist datenbankspezifisch, was bedeutet, dass Sie sie in jeder Datenbank, in der die Funktionalität benötigt wird, separat installieren müssen.

**Anmerkung**  
Bei Verbindungen, die vor der Installation dieser Erweiterung hergestellt wurden, werden weiterhin unmaskierte Daten angezeigt. Schließen Sie und stellen Sie die Verbindung erneut her, um dieses Problem zu beheben.

Überprüfen Sie die Installation der Erweiterung, indem Sie die verfügbaren Maskierungsfunktionen überprüfen:

```
SELECT proname FROM pg_proc
    WHERE pronamespace = 'pgcolumnmask'::regnamespace AND proname LIKE 'mask_%';
    proname     
--------Output --------
 mask_email
 mask_text
 mask_timestamp
(3 rows)
```

# Verfahren zur Verwaltung von Datenmaskierungsrichtlinien
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures"></a>

Sie können Maskierungsrichtlinien mithilfe der von der Erweiterung bereitgestellten Verfahren verwalten. `pg_columnmask` Um Maskierungsrichtlinien zu erstellen, zu ändern oder zu löschen, benötigen Sie eines der folgenden Rechte:
+ Besitzer der Tabelle, für die Sie die `pg_columnmask` Richtlinie erstellen.
+ Mitglied von`rds_superuser`.
+ Mitglied der durch den `pgcolumnmask.policy_admin_rolname` Parameter festgelegten Rolle des `pg_columnmask` Policy-Managers.

Mit dem folgenden Befehl wird eine Tabelle erstellt, die in nachfolgenden Abschnitten verwendet wird:

```
CREATE TABLE public.customers (
    id SERIAL PRIMARY KEY,
    name TEXT,
    phone TEXT,
    address TEXT,
    email TEXT
);
```

## CREATE\$1MASKING\$1POLICY
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures.CreateMaskingPolicy"></a>

Das folgende Verfahren erstellt eine neue Maskierungsrichtlinie für eine Benutzertabelle:

**Syntax**

```
create_masking_policy(
    policy_name,
    table_name,
    masking_expressions,
    roles,
    weight)
```

**Argumente**


| Parameter | Datatype | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  Der Name der Maskierungsrichtlinie. Muss pro Tabelle eindeutig sein.  | 
| table\$1name | REGCLASS |  Der qualified/unqualified Name oder die OID der Tabelle, auf die die Maskierungsrichtlinie angewendet werden soll.  | 
| masking\$1expressions | JSONB |  JSON-Objekt, das Paare aus Spaltennamen und Maskierungsfunktionen enthält. Jeder Schlüssel ist ein Spaltenname und sein Wert ist der Maskierungsausdruck, der auf diese Spalte angewendet werden soll.  | 
| roles | NAME [] |  Die Rollen, für die diese Maskierungsrichtlinie gilt. Die Standardeinstellung ist PUBLIC.  | 
| weight | INT |  Gewicht der Maskierungsrichtlinie. Wenn für die Anfrage eines bestimmten Benutzers mehrere Richtlinien gelten, wird die Richtlinie mit der höchsten Gewichtung (höhere Ganzzahl) auf jede maskierte Spalte angewendet. Standard = 0. Keine zwei Maskierungsrichtlinien in der Tabelle können dieselbe Gewichtung haben.  | 

**Rückgabetyp**

Keine

**Example beim Erstellen einer Maskierungsrichtlinie, die die E-Mail-Spalte für die Rolle maskiert: `test_user`**  

```
CALL pgcolumnmask.create_masking_policy(
    'customer_mask',
    'public.customers',
    JSON_OBJECT('{
        "email", "pgcolumnmask.mask_email(email)"
    }')::JSONB,
    ARRAY['test_user'],
    100
);
```

## ALTER\$1MASKING\$1POLICY
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures.AlterMaskingPolicy"></a>

Dieses Verfahren ändert eine bestehende Maskierungsrichtlinie. `ALTER_MASKING_POLICY`kann die Maskierungsausdrücke der Richtlinie, die Gruppe der Rollen, für die die Richtlinie gilt, und die Gewichtung der Maskierungsrichtlinie ändern. Wenn einer dieser Parameter weggelassen wird, bleibt der entsprechende Teil der Richtlinie unverändert.

**Syntax**

```
alter_masking_policy(
    policy_name,
    table_name,
    masking_expressions,
    roles,
    weight)
```

**Argumente**


| Parameter | Datatype | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  Bestehender Name der Maskierungsrichtlinie.  | 
| table\$1name | REGCLASS |  Die qualified/unqualified Name-OID der Tabelle, die die Maskierungsrichtlinie enthält.  | 
| masking\$1expressions | JSONB |  Neues JSON-Objekt mit Spaltennamen und Maskierungsfunktionspaaren oder andernfalls NULL.  | 
| roles | NAME [] |  Die Liste der neuen Rollen, für die diese Maskierungsrichtlinie gilt, andernfalls NULL.  | 
| weight | INT |  Neue Gewichtung für die Maskierungsrichtlinie oder andernfalls NULL.  | 

**Rückgabetyp**

Keine

**Example zum Hinzufügen der Analystenrolle zu einer vorhandenen Maskierungsrichtlinie, ohne andere Richtlinienattribute zu ändern.**  

```
CALL pgcolumnmask.alter_masking_policy(
    'customer_mask',
    'public.customers',
    NULL,
    ARRAY['test_user', 'analyst'],
    NULL 
);

-- Alter the weight of the policy without altering other details
CALL pgcolumnmask.alter_masking_policy(
    'customer_mask',
    'customers',
    NULL,
    NULL,
    4
);
```

## DROP\$1MASKING\$1POLICY
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures.DropMaskingPolicy"></a>

Durch dieses Verfahren wird eine bestehende Maskierungsrichtlinie entfernt.

**Syntax**

```
drop_masking_policy(
        policy_name,
        table_name)
```

**Argumente**


| Parameter | Datatype | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  Bestehender Name der Maskierungsrichtlinie.  | 
| table\$1name | REGCLASS |  Die qualified/unqualified Name-OID der Tabelle, die die Maskierungsrichtlinie enthält.  | 

**Rückgabetyp**

Keine

**Example beim Löschen der Maskierungsrichtlinie customer\$1mask**  

```
-- Drop a masking policy
    CALL pgcolumnmask.drop_masking_policy(
        'customer_mask',
        'public.customers',
    );
```

# Umgehen von Identifikatoren in der DDL-Prozedur für Maskierungsrichtlinien
<a name="AuroraPostgreSQL.Security.DynamicMasking.EscapeIdentifiers"></a>

Bei der Erstellung von Datenmaskierungsrichtlinien mit Identifikatoren in Anführungszeichen ist ein korrektes Escaping erforderlich, um sicherzustellen, dass die Objektverweise und die Richtlinien korrekt angewendet werden. Um Bezeichner in Anführungszeichen innerhalb der Verfahren zur Verwaltung von `pg_columnmask` Maskierungsrichtlinien zu verwenden, gehen Sie wie folgt vor:
+ **Richtlinienname** — Muss in doppelte Anführungszeichen gesetzt werden.
+ **Tabellenname** — Sowohl der Schemaname als auch der Tabellenname müssen bei Bedarf einzeln in doppelte Anführungszeichen gesetzt werden.
+ **Maskierungsausdrücke** — Spalten- und Funktionsnamen in Maskierungsausdrücken müssen in doppelte Anführungszeichen eingeschlossen werden, und die Anführungszeichen selbst müssen mit einem umgekehrten Schrägstrich maskiert werden.
+ **Rollen** — Das Array der Rollennamen wird automatisch in Anführungszeichen gesetzt. Der Rollenname sollte genau dem Namen entsprechen, wie er unter angegeben ist, `pg_roles` einschließlich Groß- und Kleinschreibung.

**Example der Syntax mit Escape-Zeichen und Anführungszeichen**  
Dieses Beispiel zeigt die richtige Syntax für Escapes und Anführungszeichen bei der Erstellung von Maskierungsrichtlinien für Tabellen, Spalten, Funktionen und Rollen, die Namen in Groß- und Kleinschreibung verwenden oder Bezeichner in Anführungszeichen in Aurora PostgreSQL erfordern.  

```
-- Create a table and columns with mixed case name 
CREATE TABLE public."Employees" (
    "Name" TEXT,
    "Email" TEXT,
    ssn VARCHAR(20)
);

-- Create a role with mixed case name
CREATE ROLE "Masked_user";

-- Create a function with mixed case name
CREATE OR REPLACE FUNCTION public."MaskEmail"(text)
    RETURNS character varying
    LANGUAGE plpgsql
    IMMUTABLE PARALLEL SAFE
    AS $$ BEGIN
        RETURN 'XXXXXXXX'::text;
    END $$;

-- Now use these objects with mixed case names in
-- masking policy management procedures
CALL pgcolumnmask.create_masking_policy(
    '"Policy1"',  -- policy name should be surrounded with double quotes for quoting
    'public."Employees"', -- table and schema name should be individually 
                          -- surrounded with double quotes for quoting
    JSON_OBJECT('{
        "\"Email\"", "\"MaskEmail\"(\"Email\")"
    }')::JSONB, -- masking expression should have double quotes around function names
                -- and columns names etc when needed. Also the double quotes itself
                -- should be escaped using \ (backslash) since this is a JSON string
    ARRAY['Masked_user'], -- Rolename do not need quoting
                          -- (this behaviour may change in future release)
    100
);

SELECT * FROM pgcolumnmask.pg_columnmask_policies
    WHERE tablename = 'Employees';
-[ RECORD 1 ]-----+-------------------------------------
schemaname        | public
tablename         | Employees
policyname        | Policy1
roles             | {Masked_user}
masked_columns    | {Email}
masking_functions | {"(\"MaskEmail\"(\"Email\"))::text"}
weight            | 100
```

## Administrative Ansichten
<a name="AuroraPostgreSQL.Security.DynamicMasking.AdminViews"></a>

Sie können die gesamte `pg_columnmask` Richtlinie in der öffentlich zugänglichen `pgcolumnmask.pg_columnmask_policies` Verwaltungsansicht überprüfen. Die folgenden Informationen sind in dieser Ansicht verfügbar. Die Ansicht gibt nur die Maskierungsrichtlinien zurück, die dem aktuellen Benutzer gehören.


| Name der Spalte | Datentyp | Beschreibung | 
| --- | --- | --- | 
|  schemaname  | NAME |  Schema der Beziehung, an die die Richtlinie angehängt ist  | 
|  tablename  | NAME |  Name der Beziehung, an die die Richtlinie angehängt ist  | 
|  Name der Richtlinie  | NAME |  Name der Maskierungsrichtlinie. Alle Maskierungsrichtlinien haben eindeutige Namen  | 
|  Rollen  | TEXT [] |  Rolle, für die die Richtlinie gilt.  | 
|  masked\$1columns  | TEXT [] |  Maskierte Spalten  | 
|  maskierende Funktionen  | TEXT [] |  Maskierungsfunktionen  | 
| Gewichtung | INT |  Gewicht der beigefügten Richtlinie  | 

# Vordefinierte Datenmaskierungsfunktionen
<a name="AuroraPostgreSQL.Security.DynamicMasking.PredefinedMaskingFunctions"></a>

`pg_columnmask`Die Erweiterung bietet integrierte Hilfsfunktionen, die in der Sprache C geschrieben sind (für eine schnellere Ausführung) und als Maskierungsausdruck für `pg_columnmask` Richtlinien verwendet werden können.

**mask\$1text**

Eine Funktion zum Maskieren von Textdaten mit konfigurierbaren Sichtbarkeitsoptionen.

**Argumente**


| Parameter | Datatype | Description | 
| --- | --- | --- | 
| input | TEXT |  Die ursprüngliche Textzeichenfolge, die maskiert werden soll  | 
| mask\$1char | CHAR (1) |  Für die Maskierung verwendetes Zeichen (Standard: 'X')  | 
| visible\$1prefix | INT |  Anzahl der Zeichen am Anfang des Eingabetextes, die unmaskiert bleiben (Standard: 0)  | 
| visible\$1suffix | INT |  Anzahl der Zeichen am Ende des Eingabetextes, die unmaskiert bleiben (Standard: 0)  | 
| use\$1hash\$1mask | BOOLEAN |  Bei TRUE wird anstelle von mask\$1char eine Hash-basierte Maskierung verwendet (Standard: FALSE)  | 

**Example der Verwendung verschiedener Maskierungsoptionen**  
Maskiert die gesamte Eingabezeichenfolge mit dem Standardzeichen 'X'  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World');
  mask_text  
-------------
 XXXXXXXXXXX
```
Verwenden Sie das `mask_char` Argument, um Texteingaben mit einem anderen Zeichen zu maskieren  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*');
  mask_text  
-------------
 ***********
```
Verwenden Sie `visible_prefix` und `visible_suffix` -Parameter, um zu steuern, wie viele Zeichen am Anfang und Ende des Textes unmaskiert bleiben  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*', 5, 1);
  mask_text  
-------------
 Hello*****d
```
Wenn wahr, `use_hash_mask` wird die Eingabezeichenfolge mit zufälligen Zeichen maskiert, `mask_char` das Argument wird ignoriert, aber trotzdem `visible_prefix` berücksichtigt `visible_suffix`  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*', 2, 2, true);
  mask_text  
-------------
 Hex36dOHild
```

**mask\$1timestamp**


| Parameter | Datatype | Description | 
| --- | --- | --- | 
| ts\$1to\$1mask | TIMESTAMP (ZEITSTEMPEL) |  Der ursprüngliche Zeitstempel, der maskiert werden soll  | 
| mask\$1part | TEXT |  Gibt an, welcher Teil des Zeitstempels maskiert werden soll (Standard: 'all') Gültige Werte: 'Jahr', 'Monat', 'Tag', 'Stunde', 'Minute', 'Sekunde', 'alles'  | 
| mask\$1value | TIMESTAMP (ZEITSTEMPEL) |  Der Zeitstempelwert, der für die Maskierung verwendet werden soll (Standard: '1900-01-01 00:00:00 ')  | 

**Example Verwendung von `mask_timestamps`**  
Diese Beispiele veranschaulichen die vollständige Maskierung des Zeitstempels auf einen Standardwert, die teilweise Maskierung bestimmter Zeitstempelkomponenten (nur Jahr) und die Maskierung mit einem benutzerdefinierten Ersatzwert.  
Maskiert den Eingabewert vollständig mit dem Standardzeitstempel  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00');
   mask_timestamp    
---------------------
 1900-01-01 00:00:00
```
Um nur einen Teil des Zeitstempels zu maskieren, zum Beispiel nur das Jahr  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00', 'year');
   mask_timestamp    
---------------------
 1900-06-15 14:30:00
```
Um den maskierten Wert für den Zeitstempel zu ändern, verwenden Sie das Argument `mask_value`  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00', 'all', '2012-12-12 12:12:12');
   mask_timestamp    
---------------------
 2012-12-12 12:12:12
```

**mask\$1timestamp**

Eine Funktion zum Maskieren von E-Mail-Adressen unter Beibehaltung der E-Mail-Struktur.


| Parameter | Datatype | Description | 
| --- | --- | --- | 
| input | TEXT |  Die ursprüngliche E-Mail-Adresse, die maskiert werden soll  | 
| mask\$1char | CHAR (1) |  Für die Maskierung verwendetes Zeichen (Standard: 'X')  | 
| mask\$1local | BOOLEAN |  Bei TRUE wird der lokale Teil der E-Mail (vor @) maskiert (Standard: TRUE)  | 
| mask\$1domain | BOOLEAN |  Bei TRUE wird der Domänenteil der E-Mail (nach @) maskiert (Standard: TRUE)  | 

**Example Verwendung von `mask_email`**  
Diese Beispiele veranschaulichen die vollständige E-Mail-Maskierung, benutzerdefinierte Maskenzeichen und die selektive Maskierung entweder des lokalen Teils oder des Domainteils der E-Mail-Adresse.  
Vollständige Maskierung  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com');
    mask_email    
------------------
 XXXX@XXXXXXX.com
```
Dient `mask_char` zum Ändern des für die Maskierung verwendeten Zeichens  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*');
    mask_email    
------------------
 ****@*******.com
```
Verwenden Sie `mask_local` und`mask_domain`, um die Maskierung auf lokaler Ebene und in der Domäne zu steuern  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*', true, false);
    mask_email    
------------------
 ****@example.com

postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*', false, true);
    mask_email    
------------------
 user@*******.com
```

# Implementierung von pg\$1columnmask in einem Workflow end-to-end
<a name="AuroraPostgreSQL.Security.DynamicMasking.WorkflowExample"></a>

In diesem Abschnitt wird eine vollständige Implementierung der `pg_columnmask` Verwendung einer Beispieltabelle für Mitarbeiter mit sensiblen Daten demonstriert. Sie erfahren, wie Sie benutzerdefinierte Maskierungsfunktionen erstellen, mehrere Maskierungsrichtlinien mit unterschiedlichen Gewichtungsstufen für verschiedene Rollen (Praktikant, Support, Analyst) definieren und beobachten, wie Benutzer mit einer oder mehreren Rollenmitgliedschaften unterschiedliche Ebenen maskierter Daten sehen. Die Beispiele behandeln auch das Maskierungsverhalten in DML-Anweisungen mit RETURNING-Klauseln, Trigger für Tabellen im Vergleich zu Ansichten und Policy-Management-Operationen wie Umbenennen, Ändern von Gewichtungen und Bereinigung.

1. Erstellen Sie eine Beispieltabelle mit einigen sensiblen Daten:

   ```
   CREATE SCHEMA hr;
   
   CREATE TABLE hr.employees (
       id INT PRIMARY KEY,
       name TEXT NOT NULL,
       email TEXT,
       ssn TEXT,
       salary NUMERIC(10,2)
    );
   
   INSERT INTO hr.employees VALUES
       (1, 'John Doe', 'john.doe@example.com', '123-45-6789', 50000.00),
       (2, 'Jane Smith', 'jane.smith@example.com', '987-65-4321', 60000.00);
   ```

1. Erstellen Sie benutzerdefinierte Maskierungsfunktionen:

   ```
   CREATE OR REPLACE FUNCTION public.mask_ssn(ssn TEXT)
       RETURNS TEXT AS $$
       BEGIN
           RETURN 'XXX-XX-' || RIGHT(ssn, 4);
       END;
       $$ LANGUAGE plpgsql;
   
   CREATE OR REPLACE FUNCTION public.mask_salary(salary NUMERIC, multiplier NUMERIC DEFAULT 0.0)
       RETURNS NUMERIC AS $$
       BEGIN
           RETURN salary * multiplier;
       END;
       $$ LANGUAGE plpgsql;
   ```

1. Erstellen Sie mehrere Richtlinien mit unterschiedlichen Maskierungsstufen, die auf den Benutzerrollen basieren:

   ```
   -- Create different roles
   CREATE ROLE analyst_role;
   CREATE ROLE support_role;
   CREATE ROLE intern_role;
   
   GRANT USAGE ON SCHEMA hr TO analyst_role, support_role, intern_role;
   GRANT SELECT ON hr.employees TO analyst_role, support_role, intern_role;
   ----------------------------------------------------------------------
   
   -- Low-Weight Policy (Intern)
   CALL pgcolumnmask.create_masking_policy(
       'employee_mask_strict',
       'hr.employees',
       JSON_BUILD_OBJECT('name', 'pgcolumnmask.mask_text(name, ''*'')',
                         'email', 'pgcolumnmask.mask_email(email)',
                         'ssn', 'pgcolumnmask.mask_text(ssn, ''*'')',
                         'salary', 'public.mask_salary(salary)')::JSONB,
       ARRAY['intern_role'],
       10  -- Lowest weight
   );
   
   ----------------------------------------------------------------------
   -- Medium-Weight Policy (Support)
   CALL pgcolumnmask.create_masking_policy(
       'employee_mask_moderate',
       'hr.employees',
       JSON_BUILD_OBJECT('email', 'pgcolumnmask.mask_email(email, ''#'')',
                         'ssn', 'public.mask_ssn(ssn)',
                         'salary', 'public.mask_salary(salary)')::JSONB,
       ARRAY['support_role'],
       50   -- Medium weight
   );
   
   ----------------------------------------------------------------------
   -- High-Weight Policy (Analyst)
   CALL pgcolumnmask.create_masking_policy(
       'employee_mask_light',
       'hr.employees',
       JSON_BUILD_OBJECT('ssn', 'public.mask_ssn(ssn)',
                         'salary', 'public.mask_salary(salary, 0.9)')::JSONB,
       ARRAY['analyst_role'],
       100   -- Highest weight
   );
   ```

1. Die folgenden Beispiele zeigen, wie verschiedene Benutzer Daten auf der Grundlage ihrer Rollenzugehörigkeit und der Gewichtung ihrer Richtlinien sehen.

   ```
   -- Create users
   CREATE USER sarah_intern;
   GRANT intern_role TO sarah_intern;
   
   CREATE USER lisa_support;
   GRANT support_role TO lisa_support;
   
   CREATE USER mike_analyst;
   GRANT analyst_role TO mike_analyst;
   
   CREATE USER ethan_support_intern;
   GRANT support_role, intern_role TO ethan_support_intern;
   
   CREATE USER john_analyst_intern;
   GRANT analyst_role, intern_role TO john_analyst_intern;
   ```

   Als Praktikant (strengste Maskierung):

   ```
   SET ROLE sarah_intern;
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     | salary 
   ----+------------+------------------------+-------------+--------
     1 | ********   | XXXXXXXX@XXXXXXX.com   | *********** |   0.00
     2 | ********** | XXXXXXXXXX@XXXXXXX.com | *********** |   0.00
   ```

   Als Support-Benutzer (moderate Maskierung):

   ```
   SET ROLE lisa_support;
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     | salary 
   ----+------------+------------------------+-------------+--------
     1 | John Doe   | ########@#######.com   | XXX-XX-6789 |   0.00
     2 | Jane Smith | ##########@#######.com | XXX-XX-4321 |   0.00
   ```

   Als Analyst (leichteste Maskierung):

   ```
   SET ROLE mike_analyst;
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     |  salary  
   ----+------------+------------------------+-------------+----------
     1 | John Doe   | john.doe@example.com   | XXX-XX-6789 | 45000.00
     2 | Jane Smith | jane.smith@example.com | XXX-XX-4321 | 54000.00
   ```

   Als ethan\$1support\$1intern-Benutzer, der sowohl Praktikant als auch Support-Benutzer ist:

   ```
   SET ROLE ethan_support_intern;
   
   -- masking policies appliable to this user: employee_mask_strict and employee_mask_moderate
   -- id : unmasked because no masking policy appliable on ethan_support_intern
   --            masks these columns
   -- name : masked because of employee_mask_strict policy
   -- email, ssn, salary : both employee_mask_strict and employee_mask_moderate mask these columns
   --                      but employee_mask_moderate will be use because of higher weight 
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     | salary 
   ----+------------+------------------------+-------------+--------
     1 | ********   | ########@#######.com   | XXX-XX-6789 |   0.00
     2 | ********** | ##########@#######.com | XXX-XX-4321 |   0.00
   ```

   Als john\$1analyst\$1intern, der sowohl Praktikant als auch Analyst ist:

   ```
   SET ROLE john_analyst_intern;
   
   -- masking policies appliable to this user: employee_mask_strict and employee_mask_light
   -- id : unmasked because no masking policy appliable on john_analyst_intern
   --            masks these columns
   -- name, email : masked because of employee_mask_strict
   -- ssn, salary : both employee_mask_strict and employee_mask_light mask these columns
   --               but employee_mask_light will be use because of higher weight 
   
   SELECT * FROM hr.employees;
    id |    name    |         email          |     ssn     |  salary  
   ----+------------+------------------------+-------------+----------
     1 | ********   | XXXXXXXX@XXXXXXX.com   | XXX-XX-6789 | 45000.00
     2 | ********** | XXXXXXXXXX@XXXXXXX.com | XXX-XX-4321 | 54000.00
   ```

# Grundlegendes zum Maskierungsverhalten bei DML-Vorgängen
<a name="AuroraPostgreSQL.Security.DynamicMasking.DMLMasking"></a>

`pg_columnmask`gilt konsistent für alle DML-Operationen, einschließlich INSERT-, UPDATE-, DELETE- und MERGE-Anweisungen. Wenn Sie diese Operationen ausführen, maskiert Aurora PostgreSQL Daten nach einem Kernprinzip: Alle aus dem Speicher gelesenen Daten werden gemäß den geltenden Richtlinien des aktuellen Benutzers maskiert.

Die Maskierung wirkt sich auf einige der folgenden Abfragekomponenten aus, z. B.:
+ WHERE-Klauseln
+ JOIN-Bedingungen
+ Unterabfragen
+ RETURNING-Klausen

Alle diese Komponenten arbeiten mit maskierten Werten, nicht mit den Originaldaten. Daten werden zwar unmaskiert in den Speicher geschrieben, Benutzer sehen jedoch nur ihre maskierte Ansicht, wenn sie sie zurücklesen.

Aurora PostgreSQL erzwingt alle Datenbankeinschränkungen (NOT NULL, UNIQUE, CHECK, FOREIGN KEY) für die tatsächlich gespeicherten Werte, nicht für maskierte Werte. Dies kann gelegentlich zu offensichtlichen Inkonsistenzen führen, wenn die Maskierungsfunktionen nicht sorgfältig entworfen wurden.

Die Maskierung funktioniert zusammen mit Berechtigungen auf Spaltenebene:
+ Benutzer ohne SELECT-Rechte können keine Spalten lesen
+ Benutzern mit SELECT-Rechten werden maskierte Werte gemäß ihren geltenden Richtlinien angezeigt

# Verstehen des Maskierungsverhaltens in Triggerfunktionen
<a name="AuroraPostgreSQL.Security.DynamicMasking.TriggerFunctionMasking"></a>

Wenn `pg_columnmask` Richtlinien auf Tabellen angewendet werden, ist es wichtig zu verstehen, wie Maskierung mit Triggerfunktionen interagiert. Trigger sind Datenbankfunktionen, die automatisch als Reaktion auf bestimmte Ereignisse in einer Tabelle ausgeführt werden, z. B. INSERT-, UPDATE- oder DELETE-Operationen.

Standardmäßig wendet DDM je nach Triggertyp unterschiedliche Maskierungsregeln an:

Tabellentrigger  
**Übergangstabellen sind unmaskiert** — Triggerfunktionen für Tabellen haben Zugriff auf unmaskierte Daten in ihren Übergangstabellen sowohl für alte als auch für neue Zeilenversionen  
Tabellenbesitzer erstellen Trigger und sind Eigentümer der Daten, sodass sie vollen Zugriff haben, um ihre Tabellen effektiv zu verwalten

Trigger anzeigen (STATT Trigger)  
**Übergangstabellen sind maskiert** — Triggerfunktionen in Ansichten sehen maskierte Daten entsprechend den Berechtigungen des aktuellen Benutzers  
Eigentümer von Ansichten können sich von Besitzern von Basistabellen unterscheiden und sollten die Maskierungsrichtlinien für die zugrunde liegenden Tabellen beachten

Zwei Konfigurationsparameter auf Serverebene steuern das Triggerverhalten bei maskierten Tabellen. Diese können nur gesetzt werden durch: `rds_superuser`
+ **Trigger für maskierte Tabellen einschränken** — Verhindert die Ausführung von Triggern, wenn ein maskierter Benutzer DML-Operationen an Tabellen mit entsprechenden Maskierungsrichtlinien ausführt.
+ **Trigger für Ansichten mit maskierten Tabellen einschränken:** — Verhindert die Ausführung von Triggern für Ansichten, wenn die Ansichtsdefinition Tabellen mit Maskierungsrichtlinien enthält, die für den aktuellen Benutzer gelten.

**Example der Unterschiede zwischen der Funktionsanwendung auf Tabelle und Ansicht**  
Im folgenden Beispiel wird eine Triggerfunktion erstellt, die alte und neue Zeilenwerte ausgibt. Anschließend wird veranschaulicht, wie sich dieselbe Funktion, wenn sie an eine Tabelle angehängt wird, anders verhält als bei einer Ansicht.  

```
-- Create trigger function
CREATE OR REPLACE FUNCTION print_changes()
    RETURNS TRIGGER AS
    $$
        BEGIN
        RAISE NOTICE 'Old row: name=%, email=%, ssn=%, salary=%',
            OLD.name, OLD.email, OLD.ssn, OLD.salary;
        
        RAISE NOTICE 'New row: name=%, email=%, ssn=%, salary=%',
            NEW.name, NEW.email, NEW.ssn, NEW.salary;
        
        RETURN NEW;
        END;
    $$ LANGUAGE plpgsql;

-- Create trigger
CREATE TRIGGER print_changes_trigger
    BEFORE UPDATE ON hr.employees
    FOR EACH ROW
    EXECUTE FUNCTION print_changes();

-- Grant update to analyst role
GRANT UPDATE ON hr.employees TO analyst_role;

-- Unmasked data must be seen inside trigger even for masked user for the OLD and NEW
-- row passed to trigger function
BEGIN;
SET ROLE mike_analyst;
UPDATE hr.employees SET id = id + 10 RETURNING *;
NOTICE:  Old row: name=John Doe, email=john.doe@example.com, ssn=123-45-6789, salary=50000.00
NOTICE:  New row: name=John Doe, email=john.doe@example.com, ssn=123-45-6789, salary=50000.00
NOTICE:  Old row: name=Jane Smith, email=jane.smith@example.com, ssn=987-65-4321, salary=60000.00
NOTICE:  New row: name=Jane Smith, email=jane.smith@example.com, ssn=987-65-4321, salary=60000.00
 id |    name    |         email          |     ssn     |  salary  
----+------------+------------------------+-------------+----------
 11 | John Doe   | john.doe@example.com   | XXX-XX-6789 | 45000.00
 12 | Jane Smith | jane.smith@example.com | XXX-XX-4321 | 54000.00
(2 rows)

ROLLBACK;


-- Triggers on views (which are supposed to see masked data for new/old row)
CREATE VIEW hr.view_over_employees AS SELECT * FROM hr.employees;
GRANT UPDATE, SELECT ON hr.view_over_employees TO analyst_role;

-- Create trigger for this view
CREATE TRIGGER print_changes_trigger
    INSTEAD OF UPDATE ON hr.view_over_employees
    FOR EACH ROW
    EXECUTE FUNCTION print_changes();

-- Masked new and old rows should be passed to trigger if trigger is on view
BEGIN;
SET ROLE mike_analyst;
UPDATE hr.view_over_employees SET id = id + 10 RETURNING *;
NOTICE:  Old row: name=John Doe, email=john.doe@example.com, ssn=XXX-XX-6789, salary=45000.00
NOTICE:  New row: name=John Doe, email=john.doe@example.com, ssn=XXX-XX-6789, salary=45000.00
NOTICE:  Old row: name=Jane Smith, email=jane.smith@example.com, ssn=XXX-XX-4321, salary=54000.00
NOTICE:  New row: name=Jane Smith, email=jane.smith@example.com, ssn=XXX-XX-4321, salary=54000.00
 id |    name    |         email          |     ssn     |  salary  
----+------------+------------------------+-------------+----------
 11 | John Doe   | john.doe@example.com   | XXX-XX-6789 | 45000.00
 12 | Jane Smith | jane.smith@example.com | XXX-XX-4321 | 54000.00
(2 rows)
ROLLBACK;
```
Wir empfehlen, das Verhalten des Triggers zu überprüfen, bevor Sie Trigger in maskierten Tabellen implementieren. Tabellen-Trigger haben Zugriff auf unmaskierte Daten in Übergangstabellen, während View-Trigger maskierte Daten sehen.

**Example der Maskierungsrichtlinie beim Umbenennen**  
Das folgende Beispiel zeigt, wie vorhandene Richtlinien mithilfe des `rename_masking_policy` Verfahrens umbenannt werden.  

```
-- Rename the strict policy
CALL pgcolumnmask.rename_masking_policy(
    'employee_mask_strict',
    'hr.employees',
    'intern_protection_policy'
);

-- Verify the rename
SELECT policyname, roles, weight
    FROM pgcolumnmask.pg_columnmask_policies
    WHERE tablename = 'employees'
    ORDER BY weight DESC;

        policyname        |     roles      | weight 
--------------------------+----------------+--------
 employee_mask_light      | {analyst_role} |    100
 employee_mask_moderate   | {support_role} |     50
 intern_protection_policy | {intern_role}  |     10
```

**Example der Änderung des politischen Gewichts**  
Das folgende Beispiel zeigt, wie das Gewicht von Policen geändert werden kann, um ihr Gewicht zu ändern.  

```
-- Change weight of moderate policy
CALL pgcolumnmask.alter_masking_policy(
    'employee_mask_moderate'::NAME,
    'hr.employees'::REGCLASS,
    NULL,    -- Keep existing masking expressions
    NULL,    -- Keep existing roles
    75       -- New weight
);

-- Verify the changes
SELECT policyname, roles, weight
    FROM pgcolumnmask.pg_columnmask_policies
    WHERE tablename = 'employees'
    ORDER BY weight DESC;
        policyname        |     roles      | weight 
--------------------------+----------------+--------
 employee_mask_light      | {analyst_role} |    100
 employee_mask_moderate   | {support_role} |     75
 intern_protection_policy | {intern_role}  |     10
```

**Example des Aufräumens**  
Das folgende Beispiel zeigt, wie alle Richtlinien, Tabellen und Benutzer gelöscht werden.  

```
-- Drop policies
CALL pgcolumnmask.drop_masking_policy(
    'intern_protection_policy',
    'hr.employees'
);

CALL pgcolumnmask.drop_masking_policy(
    'employee_mask_moderate',
    'hr.employees'
);

CALL pgcolumnmask.drop_masking_policy(
    'employee_mask_light',
    'hr.employees'
);

-- Drop table and functions
DROP VIEW IF EXISTS hr.view_over_employees;
DROP TABLE IF EXISTS hr.employees;
DROP SCHEMA IF EXISTS hr;
DROP FUNCTION IF EXISTS public.mask_ssn(text);
DROP FUNCTION IF EXISTS public.mask_salary(numeric, numeric);

-- Drop users
DROP USER sarah_intern, lisa_support, mike_analyst,
    ethan_support_intern, john_analyst_intern;
DROP ROLE intern_role, support_role, analyst_role;
```

# Verwaltungsrolle für Maskierungsrichtlinien konfigurieren
<a name="AuroraPostgreSQL.Security.DynamicMasking.PolicyManagementRole"></a>

Die PostgreSQL-Erweiterung zur Spaltenmaskierung ermöglicht es Ihnen`pg_columnmask`, die Verwaltung von Maskierungsrichtlinien an eine bestimmte Rolle zu delegieren, anstatt Tabellenbesitzerrechte zu verlangen`rds_superuser`. Dies ermöglicht eine genauere Kontrolle darüber, wer Maskierungsrichtlinien erstellen, ändern und löschen kann.

Gehen Sie wie folgt vor, um die Rolle zu konfigurieren, der Verwaltungsrechte für Maskierungsrichtlinien zugewiesen werden sollen:

1. Erstellen Sie die Rolle des Richtlinienadministrators — Erstellen Sie als Nächstes eine neue Rolle`rds_superuser`, die für die Verwaltung von Maskierungsrichtlinien zuständig ist:

   ```
   CREATE ROLE mask_admin NOLOGIN;
   ```

1. PostgreSQL-Parameter konfigurieren — Legen Sie in Ihrer benutzerdefinierten DB-Cluster-Parametergruppe den `pgcolumnmask.policy_admin_rolname` Engine-Konfigurationsparameter auf den Namen der Rolle fest, die Sie erstellt haben:

   ```
   pgcolumnmask.policy_admin_rolname = mask_admin
   ```

   Diese Engine-Konfigurationsparameter können in einer DB-Cluster-Parametergruppe festgelegt werden und erfordern keinen Instance-Neustart. Einzelheiten zur Aktualisierung des Parameters finden Sie unter[Ändern von Parametern in einer DB-Cluster-Parametergruppe in Amazon Aurora](USER_WorkingWithParamGroups.ModifyingCluster.md).

1. Weisen Sie Benutzern die Rolle zu. Weisen Sie die `mask_admin` Rolle den Benutzern zu`rds_superuser`, die in der Lage sein sollten, Maskierungsrichtlinien zu verwalten:

   ```
   CREATE USER alice LOGIN;
   CREATE USER bob LOGIN;
   GRANT mask_admin TO alice, bob;
   ```

   Stellen Sie außerdem sicher, dass die Benutzer über die USAGE-Rechte für die Schemas verfügen, in denen sie Maskierungsrichtlinien verwalten werden:

   ```
   GRANT USAGE ON SCHEMA hr TO alice, bob;
   ```

Wenn Benutzer `alice` nun `bob` eine Verbindung zur Datenbank herstellen, können sie die `pg_columnmask` Standarderweiterungsfunktionen verwenden, um Maskierungsrichtlinien für alle Tabellen in allen Schemas zu erstellen, zu ändern und zu löschen, für die sie `USAGE` Berechtigungen für das Schema haben.

# Bewährte Methoden für die sichere Implementierung von pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices"></a>

Der folgende Abschnitt enthält bewährte Sicherheitsmethoden für die Implementierung `pg_columnmask` in Ihrer Aurora PostgreSQL-Umgebung. Folgen Sie diesen Empfehlungen, um:
+ Richten Sie eine sichere, rollenbasierte Architektur für die Zugriffskontrolle ein
+ Entwickeln Sie Maskierungsfunktionen, die Sicherheitslücken verhindern
+ Verstehen und kontrollieren Sie das Triggerverhalten mit maskierten Daten

## Rollenbasierte Sicherheitsarchitektur
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.architecture"></a>

Definieren Sie eine Rollenhierarchie, um Zugriffskontrollen in Ihrer Datenbank zu implementieren. Aurora PostgreSQL `pg_columnmask` erweitert diese Kontrollen, indem es eine zusätzliche Ebene für die feinkörnige Datenmaskierung innerhalb dieser Rollen bereitstellt.

Erstellen Sie spezielle Rollen, die auf die Unternehmensfunktionen abgestimmt sind, anstatt einzelnen Benutzern Berechtigungen zu gewähren. Dieser Ansatz bietet eine bessere Überprüfbarkeit und vereinfacht das Berechtigungsmanagement, wenn sich Ihre Organisationsstruktur weiterentwickelt.

**Example der Schaffung einer organisatorischen Rollenhierarchie**  
Im folgenden Beispiel wird eine organisatorische Rollenhierarchie mit speziellen Rollen für verschiedene Funktionen erstellt und anschließend einzelnen Benutzern die entsprechenden Rollen zugewiesen. In diesem Beispiel werden zuerst Organisationsrollen (analyst\$1role, support\$1role) erstellt, dann wird einzelnen Benutzern die Mitgliedschaft in diesen Rollen gewährt. Diese Struktur ermöglicht es Ihnen, Berechtigungen auf Rollenebene und nicht für jeden einzelnen Benutzer zu verwalten.  

```
-- Create organizational role hierarchy
CREATE ROLE data_admin_role;
CREATE ROLE security_admin_role;
CREATE ROLE analyst_role;
CREATE ROLE support_role;
CREATE ROLE developer_role;

-- Specify security_admin_role as masking policy manager in the DB cluster parameter
-- group pgcolumnmask.policy_admin_rolname = 'security_admin_role'

-- Create specific users and assign to appropriate roles
CREATE USER security_manager;
CREATE USER data_analyst1, data_analyst2;
CREATE USER support_agent1, support_agent2;

GRANT security_admin_role TO security_manager;
GRANT analyst_role TO data_analyst1, data_analyst2;
GRANT support_role TO support_agent1, support_agent2;
```
Implementieren Sie das Prinzip der geringsten Rechte, indem Sie nur die für jede Rolle erforderlichen Mindestberechtigungen gewähren. Vermeiden Sie die Gewährung umfassender Berechtigungen, die ausgenutzt werden könnten, wenn Anmeldeinformationen kompromittiert werden.  

```
-- Grant specific table permissions rather than schema-wide access
GRANT SELECT ON sensitive_data.customers TO analyst_role;
GRANT SELECT ON sensitive_data.transactions TO analyst_role;
-- Do not grant: GRANT ALL ON SCHEMA sensitive_data TO analyst_role;
```
Richtlinienadministratoren benötigen `USAGE` Rechte für Schemas, in denen sie Maskierungsrichtlinien verwalten. Gewähren Sie diese Rechte selektiv und folgen Sie dabei dem Prinzip der geringsten Rechte. Führen Sie regelmäßige Überprüfungen der Schemazugriffsberechtigungen durch, um sicherzustellen, dass nur autorisiertes Personal über die Funktionen zur Richtlinienverwaltung verfügt.  
Die Konfiguration der Rollenparameter des Policy-Administrators ist nur auf Datenbankadministratoren beschränkt. Dieser Parameter kann nicht auf Datenbank- oder Sitzungsebene geändert werden, wodurch verhindert wird, dass Benutzer ohne Benutzerrechte die Zuweisungen von Richtlinienadministratoren außer Kraft setzen. Diese Einschränkung stellt sicher, dass die Kontrolle der Maskierungsrichtlinien zentralisiert und sicher bleibt.  
Weisen Sie die Rolle des Richtlinienadministrators bestimmten Personen und nicht Gruppen zu. Dieser gezielte Ansatz gewährleistet einen selektiven Zugriff auf die Verwaltung von Maskierungsrichtlinien, da Richtlinienadministratoren alle Tabellen in der Datenbank maskieren können. 

## Entwicklung sicherer Maskierungsfunktionen
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.MaskingDevelopment"></a>

Entwickeln Sie Maskierungsfunktionen unter Verwendung von Semantik für frühe Bindungen, um eine korrekte Nachverfolgung von Abhängigkeiten sicherzustellen und Sicherheitslücken bei späten Bindungen zu vermeiden, z. B. die Änderung von Suchpfaden während der Laufzeit. Es wird empfohlen, die `BEGIN ATOMIC` Syntax für SQL-Funktionen zu verwenden, um die Validierung während der Kompilierung (d. h. frühes Binden) und das Abhängigkeitsmanagement zu ermöglichen.

```
-- Example - Secure masking function with early binding
CREATE OR REPLACE FUNCTION secure_mask_ssn(input_ssn TEXT)
    RETURNS TEXT
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    BEGIN ATOMIC
        SELECT CASE
            WHEN input_ssn IS NULL THEN NULL
            WHEN length(input_ssn) < 4 THEN repeat('X', length(input_ssn))
            ELSE repeat('X', length(input_ssn) - 4) || right(input_ssn, 4)
        END;
    END;
```

Alternativ können Sie Funktionen erstellen, die immun gegen Änderungen des Suchpfads sind, indem Sie alle Objektreferenzen explizit per Schema qualifizieren und so ein konsistentes Verhalten über verschiedene Benutzersitzungen hinweg sicherstellen.

```
-- Function immune to search path changes
CREATE OR REPLACE FUNCTION data_masking.secure_phone_mask(phone_number TEXT)
    RETURNS TEXT
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    AS $$
    SELECT CASE
        WHEN phone_number IS NULL THEN NULL
        WHEN public.length(public.regexp_replace(phone_number, '[^0-9]', '', 'g')) < 10 THEN 'XXX-XXX-XXXX'
        ELSE public.regexp_replace(
            phone_number,
            '([0-9]{3})[0-9]{3}([0-9]{4})',
            public.concat('\1-XXX-\2')
        )
    END;
    $$;
```

Implementieren Sie die Eingabevalidierung innerhalb von Maskierungsfunktionen, um Sonderfälle zu behandeln und unerwartetes Verhalten zu verhindern. Schließen Sie immer die NULL-Behandlung ein und validieren Sie die Eingabeformate, um ein konsistentes Maskierungsverhalten sicherzustellen. 

```
-- Robust masking function with comprehensive input validation
CREATE OR REPLACE FUNCTION secure_mask_phone(phone_number TEXT)
    RETURNS TEXT
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    BEGIN ATOMIC
        SELECT CASE
            WHEN phone_number IS NULL THEN NULL
            WHEN length(trim(phone_number)) = 0 THEN phone_number
            WHEN length(regexp_replace(phone_number, '[^0-9]', '', 'g')) < 10 THEN 'XXX-XXX-XXXX'
            ELSE regexp_replace(phone_number, '([0-9]{3})[0-9]{3}([0-9]{4})', '\1-XXX-\2')
        END;
    END;
```

## DML löst Verhalten mit pg\$1columnmask aus
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.DMLTriggerBehavior"></a>

Bei Tabellentriggern werden Übergangstabellen vollständig demaskiert. Bei View-Triggern (IOT) werden Übergangstabellen entsprechend den Anzeigeberechtigungen des aktuellen Benutzers maskiert.

Tabellentrigger werden mit pg\$1columnmask ausgelöst  
Triggern wird eine Übergangstabelle übergeben, die die alte und die neue Version der Zeilen enthält, die durch die auslösende DML-Abfrage geändert wurden. Je nachdem, wann der Trigger ausgelöst wird, füllt Aurora PostgreSQL die alten und neuen Zeilen auf. Ein `BEFORE INSERT` Trigger hat beispielsweise nur neue Versionen der Zeilen und leere alte Versionen, weil es keine alte Version gibt, auf die verwiesen werden kann.  
`pg_columnmask`maskiert keine Übergangstabellen innerhalb von Triggern für Tabellen. Trigger können maskierte Spalten in ihrem Hauptteil verwenden, und es werden unmaskierte Daten angezeigt. Der Ersteller des Triggers sollte sicherstellen, wie der Trigger für einen Benutzer ausgeführt wird. Das folgende Beispiel funktioniert in diesem Fall korrekt.  

```
-- Example for table trigger uses masked column in its definition
-- Create a table and insert some rows
CREATE TABLE public.credit_card_table (
    name TEXT,
    credit_card_no VARCHAR(16),
    is_fraud BOOL
);

INSERT INTO public.credit_card_table (name, credit_card_no, is_fraud)
    VALUES
    ('John Doe', '4532015112830366', false),
    ('Jane Smith', '5410000000000000', true),
    ('Brad Smith', '1234567891234567', true);

-- Create a role which will see masked data and grant it privileges
CREATE ROLE intern_user;
GRANT SELECT, DELETE ON public.credit_card_table TO intern_user;

-- Trigger which will silenty skip delete of non fraudelent credit cards
CREATE OR REPLACE FUNCTION prevent_non_fraud_delete()
    RETURNS TRIGGER AS
    $$
    BEGIN
        IF OLD.is_fraud = false THEN
            RETURN NULL;
        END IF;
        RETURN OLD;
    END;
    $$ LANGUAGE plpgsql;

CREATE TRIGGER prevent_non_fraud_delete
    BEFORE DELETE ON credit_card_table
    FOR EACH ROW
    EXECUTE FUNCTION prevent_non_fraud_delete();

CREATE OR REPLACE FUNCTION public.return_false()
    RETURNS BOOLEAN
    LANGUAGE SQL
    IMMUTABLE PARALLEL SAFE STRICT
    BEGIN ATOMIC
      SELECT false;
    END;

-- A masking policy that masks both credit card number and is_fraud column.
-- If we apply masking inside trigger then prevent_non_fraud_delete trigger will
-- allow deleting more rows to masked user (even non fraud ones).
CALL pgcolumnmask.create_masking_policy(
    'mask_credit_card_no_&_is_fraud'::NAME,
    'public.credit_card_table'::REGCLASS,
    JSON_BUILD_OBJECT('credit_card_no', 'pgcolumnmask.mask_text(credit_card_no)',
                      'is_fraud', 'public.return_false()')::JSONB,
    ARRAY['intern_user']::NAME[],
    10::INT
);

-- Test trigger behaviour using intern_user
BEGIN;
SET ROLE intern_user;
-- credit card number & is_fraud is completely masked from intern_user
SELECT * FROM public.credit_card_table;
    name    |  credit_card_no  | is_fraud 
------------+------------------+----------
 John Doe   | XXXXXXXXXXXXXXXX | f
 Jane Smith | XXXXXXXXXXXXXXXX | f
 Brad Smith | XXXXXXXXXXXXXXXX | f
(3 rows)

-- The delete trigger lets the intern user delete rows for Jane and Brad even though
-- intern_user sees their is_fraud = false, but the table trigger works with original
-- unmasked value
DELETE FROM public.credit_card_table RETURNING *;
    name    |  credit_card_no  | is_fraud 
------------+------------------+----------
 Jane Smith | XXXXXXXXXXXXXXXX | f
 Brad Smith | XXXXXXXXXXXXXXXX | f
(2 rows)

COMMIT;
```
Der Trigger-Ersteller gibt unmaskierte Daten an den Benutzer weiter, wenn er nicht vorsichtig mit den Anweisungen umgeht, die er in seinem Triggertext verwendet. Wenn Sie beispielsweise a verwenden, wird `RAISE NOTICE ‘%’, masked_column;` die Spalte an den aktuellen Benutzer ausgegeben.  

```
-- Example showing table trigger leaking column value to current user
CREATE OR REPLACE FUNCTION leaky_trigger_func()
    RETURNS TRIGGER AS
    $$
    BEGIN
        RAISE NOTICE 'Old credit card number was: %', OLD.credit_card_no;
        RAISE NOTICE 'New credit card number is %', NEW.credit_card_no;
        RETURN NEW;
    END;
    $$ LANGUAGE plpgsql;

CREATE TRIGGER leaky_trigger
    AFTER UPDATE ON public.credit_card_table
    FOR EACH ROW
    EXECUTE FUNCTION leaky_trigger_func();

-- Grant update on column is_fraud to auditor role
-- auditor will NOT HAVE PERMISSION TO READ DATA
CREATE ROLE auditor;
GRANT UPDATE (is_fraud) ON public.credit_card_table TO auditor;

-- Also add auditor role to existing masking policy on credit card table
CALL pgcolumnmask.alter_masking_policy(
    'mask_credit_card_no_&_is_fraud'::NAME,
    'public.credit_card_table'::REGCLASS,
    NULL::JSONB,
    ARRAY['intern_user', 'auditor']::NAME[],
    NULL::INT
);

-- Log in as auditor
-- [auditor]
-- Update will fail if trying to read data from the table
UPDATE public.credit_card_table
    SET is_fraud = true
    WHERE credit_card_no = '4532015112830366';
ERROR:  permission denied for table cc_table

-- [auditor]
-- But leaky update trigger will still print the entire row even though
-- current user does not have permission to select from public.credit_card_table
UPDATE public.credit_card_table SET is_fraud = true;
NOTICE:  Old credit_card_no was: 4532015112830366
NOTICE:  New credit_card_no is 4532015112830366
```

Wird bei Ansichten mit pg\$1columnmask ausgelöst (anstelle von Triggern)  
Trigger können nur für Ansichten in PostgreSQL erstellt werden. Sie werden für die Ausführung von DML-Anweisungen in Ansichten verwendet, die nicht aktualisierbar sind. Transittabellen werden immer intern maskiert und nicht innerhalb von Triggern (IOT), da die in der View-Abfrage verwendete View und die Basistabellen unterschiedliche Besitzer haben können. In diesem Fall können für Basistabellen einige Maskierungsrichtlinien gelten, die für den Eigentümer der Ansicht gelten, und der Eigentümer der Ansicht muss in seinen Triggern immer maskierte Daten aus Basistabellen sehen. Dies unterscheidet sich von Triggern für Tabellen, da in diesem Fall der Trigger-Ersteller und die Daten in den Tabellen demselben Benutzer gehören, was hier nicht der Fall ist.  

```
-- Create a view over credit card table
CREATE OR REPLACE VIEW public.credit_card_view
    AS
    SELECT * FROM public.credit_card_table;

-- Truncate credit card table and insert fresh data
TRUNCATE TABLE public.credit_card_table;
INSERT INTO public.credit_card_table (name, credit_card_no, is_fraud)
    VALUES
    ('John Doe', '4532015112830366', false),
    ('Jane Smith', '5410000000000000', true),
    ('Brad Smith', '1234567891234567', true);

CREATE OR REPLACE FUNCTION public.print_changes()
    RETURNS TRIGGER AS
    $$
    BEGIN
        RAISE NOTICE 'Old row: name=%, credit card number=%, is fraud=%',
            OLD.name, OLD.credit_card_no, OLD.is_fraud;
    
        RAISE NOTICE 'New row: name=%, credit card number=%, is fraud=%',
            NEW.name, NEW.credit_card_no, NEW.is_fraud;
    
    RETURN NEW;
   END;
   $$ LANGUAGE plpgsql;

CREATE TRIGGER print_changes_trigger
    INSTEAD OF UPDATE ON public.credit_card_view
    FOR EACH ROW
    EXECUTE FUNCTION public.print_changes();

GRANT SELECT, UPDATE ON public.credit_card_view TO auditor;

-- [auditor]
-- Login as auditor role
BEGIN;

-- Any data coming out from the table will be masked in instead of triggers
-- according to masking policies applicable to current user
UPDATE public.credit_card_view
    SET name = CONCAT(name, '_new_name')
    RETURNING *;
NOTICE:  Old row: name=John Doe, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=John Doe_new_name, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  Old row: name=Jane Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Jane Smith_new_name, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  Old row: name=Brad Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Brad Smith_new_name, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
        name         |  credit_card_no  | is_fraud 
---------------------+------------------+----------
 John Doe_new_name   | XXXXXXXXXXXXXXXX | f
 Jane Smith_new_name | XXXXXXXXXXXXXXXX | f
 Brad Smith_new_name | XXXXXXXXXXXXXXXX | f
 
 -- Any new data going into the table using INSERT or UPDATE command will be unmasked
 UPDATE public.credit_card_view
    SET credit_card_no = '9876987698769876'
    RETURNING *;
NOTICE:  Old row: name=John Doe, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=John Doe, credit card number=9876987698769876, is fraud=f
NOTICE:  Old row: name=Jane Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Jane Smith, credit card number=9876987698769876, is fraud=f
NOTICE:  Old row: name=Brad Smith, credit card number=XXXXXXXXXXXXXXXX, is fraud=f
NOTICE:  New row: name=Brad Smith, credit card number=9876987698769876, is fraud=f
    name    |  credit_card_no  | is_fraud 
------------+------------------+----------
 John Doe   | 9876987698769876 | f
 Jane Smith | 9876987698769876 | f
 Brad Smith | 9876987698769876 | f
 
 COMMIT;
```

Datenbank-/Benutzerebene zur Steuerung des GuCs Triggerverhaltens  
Zwei Konfigurationsparameter steuern das Trigger-Ausführungsverhalten für Benutzer mit entsprechenden Maskierungsrichtlinien. Verwenden Sie diese Parameter, um zu verhindern, dass Trigger in maskierten Tabellen oder Ansichten ausgeführt werden, wenn zusätzliche Sicherheitseinschränkungen erforderlich sind. Beide Parameter sind standardmäßig deaktiviert, sodass Trigger normal ausgeführt werden können.  
**Erster GUC: Beschränkung der Triggerauslösung für maskierte Tabellen**  
Spezifikationen:  
+ Name: `pgcolumnmask.restrict_dml_triggers_for_masked_users`
+ Typ: `boolean`
+ Standard: `false` (Trigger dürfen ausgeführt werden)
Wenn dieser Wert auf TRUE gesetzt ist, wird die Ausführung von Triggern in maskierten Tabellen für maskierte Benutzer verhindert. `pg_columnmask`durchläuft den Fehler.  
**Zweiter GUC: Einschränkung beim Auslösen von Triggern für Ansichten mit maskierten Tabellen**  
Spezifikationen:  
+ Name: `pgcolumnmask.restrict_iot_triggers_for_masked_users`
+ Typ: `boolean`
+ Standard: `false` (Trigger dürfen ausgeführt werden)
Wenn der Wert auf TRUE gesetzt ist, wird die Ausführung von Triggern in Ansichten verhindert, deren Definition maskierte Tabellen für maskierte Benutzer enthält.

Diese Parameter funktionieren unabhängig voneinander und sind wie standardmäßige Datenbankkonfigurationsparameter konfigurierbar.

# Aurora PostgreSQL pg\$1columnmask Datenverschiebungsszenarien
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement"></a>

`pg_columnmask`Das Verhalten variiert bei verschiedenen Datenverschiebungsvorgängen, je nachdem, ob der Vorgang auf der Speicher-, logischen oder Anwendungsebene stattfindet. Operationen auf Speicherebene (wie das Klonen) verhalten sich anders als logische Operationen (z. B.`pg_dump`) und Operationen auf Anwendungsebene (wie FDW-Abfragen). In diesem Abschnitt wird das Maskierungsverhalten für gängige Szenarien wie Replikation, Backups, Exporte und Migrationen beschrieben und die jeweiligen Sicherheitsauswirkungen erläutert.

**Topics**
+ [Aurora Global Database und Read Replicas](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR)
+ [Datenbankklon und Snapshot-Wiederherstellung](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones)
+ [Logische Replikation](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep)
+ [Blau/Grün-Bereitstellungen](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen)
+ [Zero-ETL- und CDC-Streams](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL)
+ [AWS Database Migration Service](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DMS)
+ [Datenexporte](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport)
+ [Ansichten und materialisierte Ansichten](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views)
+ [Daten speichern und wiederherstellen](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR)
+ [Wrapper für ausländische Daten](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ)

## Aurora Global Database und Read Replicas
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR"></a>

`pg_columnmask`Aurora-Richtlinien werden in Datenbanksystemtabellen innerhalb des Cluster-Volumes gespeichert. Alle Replikate greifen auf dieselben Richtlinien zu und geben konsistent maskierte Ergebnisse zurück. Bei Bereitstellungen von Aurora Global Database werden `pg_columnmask` Richtlinien AWS-Regionen zusammen mit anderen Datenbanksystemtabellen auf sekundäre Daten repliziert, wodurch ein konsistenter Datenschutz in allen Regionen gewährleistet wird. In Failover-Szenarien bleiben alle `pg_columnmask` Richtlinien intakt und funktionsfähig.

## Datenbankklon und Snapshot-Wiederherstellung
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones"></a>

Bei Aurora Fast Clone- und Snapshot-Wiederherstellungsvorgängen werden alle `pg_columnmask` Richtlinien, Rollen und Konfigurationen als Teil der Datenbanksystemtabellen beibehalten. Die geklonte oder wiederhergestellte Datenbank erbt alle vorhandenen Richtlinien aus dem Quellcluster. Nach dem Klonen oder Wiederherstellen behält jeder Datenbankcluster unabhängige Richtlinien bei. `pg_columnmask`

## Logische Replikation
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep"></a>

Während der ersten Synchronisation verwendet die logische Replikation standardmäßige SQL COPY-Operationen, und `pg_columnmask` Richtlinien werden auf der Grundlage der Berechtigungen des Replikationsbenutzers durchgesetzt. Während der laufenden CDC (Change Data Capture) werden keine Maskierungsrichtlinien angewendet und unmaskierte Daten werden über WAL-Datensätze repliziert. Benutzer mit `pg_create_subscription` Rechten können möglicherweise unmaskierte Daten exfiltrieren, indem sie die Replikation auf ein von ihnen kontrolliertes System einrichten.

## Blau/Grün-Bereitstellungen
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen"></a>

Bei der Wiederherstellung von Snapshots werden `pg_columnmask` Richtlinien automatisch berücksichtigt. Die grüne Umgebung beginnt mit einer identischen Kopie aller Richtlinien aus der blauen Umgebung. Bei der Replikation von blau nach grün werden Daten nicht maskiert. Nachfolgende Änderungen der Maskierungsrichtlinien (DDL-Befehle) auf dem blauen Cluster werden nicht auf den grünen Cluster repliziert und machen RDS-Bereitstellungen ungültig. blue/green 

## Zero-ETL- und CDC-Streams
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL"></a>

Die Datenreplikation wird durch Richtlinien nicht beeinträchtigt. `pg_columnmask` Zero-ETL unterstützt die DDL-Replikation, aber keine `pg_columnmask` Replikations- oder RLS-Richtlinien. In Zero-ETL werden keine Maskierungsrichtlinien auf replizierte Daten angewendet.

## AWS Database Migration Service
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DMS"></a>

Die anfängliche Datensynchronisierung wird je nach dem für die DMS-Aufgabe ausgewählten Benutzer maskiert oder entlarvt. CDC-Daten werden immer demaskiert. `pg_columnmask`Verwandte interne RLS-Richtlinien können zwar migriert werden, sie funktionieren jedoch nicht auf Zielen, die nicht pg\$1columnmask-fähig sind.

## Datenexporte
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport"></a>

`pg_columnmask`behandelt Exporte wie jede andere Abfrageoperation — die Maskierung wird auf der Grundlage der Berechtigungen des ausführenden Benutzers angewendet. Dies gilt für SQL-Befehle wie COPY, SELECT INTO, CREATE TABLE AS und die S3-Exportfunktion von Aurora PostgreSQL. 

**Anmerkung**  
Wenn maskierte Benutzer Daten exportieren, enthalten die resultierenden Dateien maskierte Werte, die bei der Wiederherstellung gegen Datenbankbeschränkungen verstoßen können.

## Ansichten und materialisierte Ansichten
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views"></a>

Beachten Sie bei der Verwendung von Ansichten die folgenden Überlegungen:
+ **Reguläre Ansichten** — Verwenden Sie immer `INVOKER` Semantik. Die Maskierungsrichtlinien des aktuellen Benutzers gelten bei der Abfrage der Ansicht, unabhängig davon, wer die Ansicht erstellt hat.
+ **Materialisierte Ansichten** — Bei der Aktualisierung gelten die Maskierungsrichtlinien des Besitzers der materialisierten Ansicht, nicht die Richtlinien des Benutzers, der die Aktualisierung durchführt. Wenn der Besitzer über Maskierungsrichtlinien verfügt, enthält die materialisierte Ansicht immer maskierte Daten.

## Daten speichern und wiederherstellen
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR"></a>

`pg_dump`arbeitet wie ein normaler Datenbankbenutzer und wendet Maskierungsrichtlinien an, die auf den Berechtigungen des verbindenden Benutzers basieren. Wenn ein maskierter Benutzer einen Speicherauszug durchführt, enthält die Sicherungsdatei maskierte Daten. `pg_columnmask`Richtlinien sind im Dump als Teil des Datenbankschemas enthalten. Eine erfolgreiche Wiederherstellung setzt voraus, dass alle referenzierten Rollen in der Zieldatenbank vorhanden sind und dass die `pg_columnmask` Erweiterung auf dem Ziel installiert ist.

**Anmerkung**  
`pg_dump`Unterstützt ab PostgreSQL 18 die `—no-policies` Option, die sowohl Row Level Security (RLS) als auch `pg_columnmask` Maskierungsrichtlinien von Datenbank-Dumps ausschließt. [Weitere Informationen finden Sie unter pg\$1dump.](https://www.postgresql.org/docs/current/app-pgdump.html)

## Wrapper für ausländische Daten
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ"></a>

Bei der Verwendung von Fremddaten-Wrappern werden Maskierungsrichtlinien auf Remotetabellen auf der Grundlage der Berechtigungen des zugewiesenen Benutzers auf dem Quellserver angewendet, nicht auf den Berechtigungen des lokalen abfragenden Benutzers. Sie können zwar über FDW auf maskierte Remotedaten zugreifen, aber Sie können DDM- oder RLS-Richtlinien nicht direkt für Fremdtabellen in Ihrer lokalen Datenbank erstellen.