

Le traduzioni sono generate tramite traduzione automatica. In caso di conflitto tra il contenuto di una traduzione e la versione originale in Inglese, quest'ultima prevarrà.

# Utilizzo del mascheramento dinamico con Aurora PostgreSQL
<a name="AuroraPostgreSQL.Security.DynamicMasking"></a>

Il mascheramento dinamico dei dati è una funzionalità di sicurezza che protegge i dati sensibili nei database Aurora PostgreSQL controllando il modo in cui i dati vengono visualizzati dagli utenti al momento della query. Aurora lo implementa tramite l'estensione. `pg_columnmask` `pg_columnmask`offre una protezione dei dati a livello di colonna che integra la sicurezza nativa a livello di riga di PostgreSQL e i meccanismi di controllo granulare degli accessi.

Con`pg_columnmask`, crei policy di mascheramento che determinano la visibilità dei dati in base ai ruoli degli utenti. Quando gli utenti interrogano tabelle con policy di mascheramento, Aurora PostgreSQL applica la funzione di mascheramento appropriata al momento della query in base al ruolo e al peso delle policy dell'utente. I dati sottostanti rimangono invariati nell'archiviazione.

`pg_columnmask`supporta le seguenti funzionalità:
+ Funzioni di **mascheramento integrate e personalizzate: utilizza funzioni** predefinite per modelli comuni come il mascheramento di e-mail e testo oppure crea funzioni personalizzate per proteggere i dati sensibili (PII) tramite politiche di mascheramento basate su SQL.
+ **Strategie di mascheramento multiple**: nascondi completamente le informazioni, sostituisci i valori parziali con caratteri jolly o definisci approcci di mascheramento personalizzati.
+ Assegnazione di **priorità alle politiche**: definisci più politiche per una singola colonna. Utilizza i pesi per determinare quale politica di mascheramento deve essere utilizzata quando più politiche si applicano a una colonna. Aurora PostgreSQL applica politiche basate sul peso e sull'appartenenza al ruolo dell'utente. 

`pg_columnmask`è disponibile su Aurora PostgreSQL versione 16.10 e successive e versione 17.6 e successive. È disponibile senza costi aggiuntivi.

# Guida introduttiva al mascheramento dinamico
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted"></a>

Per mascherare dinamicamente i dati, installate l'`pg_columnmask`estensione nel database e create politiche di mascheramento per le tabelle. Il processo di configurazione prevede la verifica dei prerequisiti, l'installazione dell'estensione, la configurazione dei ruoli, la creazione di policy e il test di convalida.

## Installazione e configurazione delle estensioni
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted.Installation"></a>

Connettiti al tuo cluster Aurora PostgreSQL utilizzando RDS Console Query Editor o un client PostgreSQL come psql con credenziali rds\$1superuser (utente principale).

Esegui `pg_columnmask` il comando di creazione dell'estensione per abilitare la funzionalità:

```
CREATE EXTENSION pg_columnmask;
```

Questo comando installa l'`pg_columnmask`estensione, crea le tabelle di catalogo necessarie e registra le funzioni di mascheramento integrate. L'installazione dell'estensione è specifica del database, il che significa che è necessario installarla separatamente in ogni database in cui è richiesta la funzionalità.

**Nota**  
Le connessioni effettuate prima dell'installazione di questa estensione mostreranno comunque i dati non mascherati. Chiudi e riconnettiti per risolvere il problema.

Verifica l'installazione dell'estensione controllando le funzioni di mascheramento disponibili:

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

# Procedure per la gestione delle politiche di mascheramento dei dati
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures"></a>

È possibile gestire le politiche di mascheramento utilizzando le procedure fornite dall'`pg_columnmask`estensione. Per creare, modificare o eliminare le politiche di mascheramento, è necessario disporre di uno dei seguenti privilegi:
+ Proprietario della tabella su cui si sta creando la `pg_columnmask` politica.
+ Membro di`rds_superuser`.
+ Membro del ruolo di `pg_columnmask` policy manager impostato dal `pgcolumnmask.policy_admin_rolname` parametro.

Il comando seguente crea una tabella che viene utilizzata nelle sezioni successive:

```
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>

La procedura seguente crea una nuova politica di mascheramento per una tabella utente:

**Sintassi**

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

**Arguments (Argomenti)**


| Parametro | DataType | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  Nome della policy di mascheramento. Deve essere unico per tabella.  | 
| table\$1name | REGCLASS |  Il qualified/unqualified nome o l'ID della tabella a cui applicare la politica di mascheramento.  | 
| masking\$1expressions | JSONB |  Oggetto JSON contenente il nome della colonna e le coppie di funzioni di mascheramento. Ogni chiave è un nome di colonna e il suo valore è l'espressione di mascheramento da applicare su quella colonna.  | 
| roles | NOME [] |  I ruoli a cui si applica questa politica di mascheramento. L'impostazione predefinita è PUBLIC.  | 
| weight | INT |  Peso della politica di mascheramento. Quando sono applicabili più criteri a una determinata query dell'utente, il criterio con il peso più elevato (numero intero più alto) verrà applicato a ciascuna colonna mascherata. Il valore predefinito è 0. Non esistono due politiche di mascheramento sulla tabella che possono avere lo stesso peso.  | 

**Tipo restituito**

Nessuno

**Example di creare una politica di mascheramento che maschera la colonna di posta elettronica per il ruolo: `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>

Questa procedura modifica una politica di mascheramento esistente. `ALTER_MASKING_POLICY`può modificare le espressioni di mascheramento delle policy, l'insieme di ruoli a cui si applica la policy e il peso della policy di mascheramento. Quando uno di questi parametri viene omesso, la parte corrispondente della politica rimane invariata.

**Sintassi**

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

**Arguments (Argomenti)**


| Parametro | DataType | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  Nome esistente della politica di mascheramento.  | 
| table\$1name | REGCLASS |  Il qualified/unqualified nome id della tabella contenente la politica di mascheramento.  | 
| masking\$1expressions | JSONB |  Nuovo oggetto JSON contenente il nome della colonna e le coppie di funzioni di mascheramento o NULL in caso contrario.  | 
| roles | NOME [] |  L'elenco dei nuovi ruoli a cui si applica questa politica di mascheramento o NULL in caso contrario.  | 
| weight | INT |  Nuovo peso per la politica di mascheramento o NULL in caso contrario.  | 

**Tipo restituito**

Nessuno

**Example di aggiungere il ruolo di analista a una politica di mascheramento esistente senza modificare altri attributi della politica.**  

```
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>

Questa procedura rimuove una politica di mascheramento esistente.

**Sintassi**

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

**Arguments (Argomenti)**


| Parametro | DataType | Description | 
| --- | --- | --- | 
| policy\$1name | NAME |  Nome esistente della politica di mascheramento.  | 
| table\$1name | REGCLASS |  Il qualified/unqualified nome id della tabella contenente la politica di mascheramento.  | 

**Tipo restituito**

Nessuno

**Example di eliminare la politica di mascheramento customer\$1mask**  

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

# Identificatori di escape nella procedura DDL della politica di mascheramento
<a name="AuroraPostgreSQL.Security.DynamicMasking.EscapeIdentifiers"></a>

Quando si creano policy di mascheramento dei dati con identificatori tra virgolette, è necessario un corretto escape per garantire i riferimenti agli oggetti e l'applicazione delle policy corretti. Per utilizzare gli identificatori tra virgolette all'interno delle procedure di gestione delle policy di mascheramento: `pg_columnmask`
+ **Nome della politica**: deve essere racchiuso tra virgolette doppie.
+ **Nome tabella**: sia il nome dello schema che il nome della tabella devono essere racchiusi tra virgolette doppie singolarmente, se necessario.
+ **Espressioni di mascheramento**: i nomi delle colonne e delle funzioni nelle espressioni di mascheramento devono essere racchiusi tra virgolette doppie e le virgolette stesse devono essere eliminate utilizzando una barra rovesciata.
+ **Ruoli: la matrice dei nomi dei ruoli** viene citata automaticamente. Il nome del ruolo deve corrispondere esattamente al nome indicato, `pg_roles` inclusa la distinzione tra maiuscole e minuscole.

**Example della sintassi in escape e tra virgolette**  
Questo esempio mostra la sintassi corretta di escape e virgolette quando si creano policy di mascheramento per tabelle, colonne, funzioni e ruoli che utilizzano nomi composti da maiuscole e minuscole o richiedono identificatori tra virgolette in Aurora PostgreSQL.  

```
-- 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
```

## Viste amministrative
<a name="AuroraPostgreSQL.Security.DynamicMasking.AdminViews"></a>

È possibile rivedere tutta la `pg_columnmask` politica utilizzando la visualizzazione `pgcolumnmask.pg_columnmask_policies` amministrativa accessibile al pubblico. Le seguenti informazioni sono disponibili utilizzando questa visualizzazione. La vista restituisce solo le politiche di mascheramento di proprietà dell'utente corrente.


| Nome della colonna | Tipo di dati | Description | 
| --- | --- | --- | 
|  schemaname  | NAME |  Schema della relazione a cui è allegata la politica  | 
|  tablename  | NAME |  Nome della relazione a cui è allegata la politica  | 
|  nome della politica  | NAME |  Nome della politica di mascheramento, tutte le politiche di mascheramento hanno nomi univoci  | 
|  roles  | TESTO [] |  Ruolo a cui si applica la politica.  | 
|  masked\$1columns  | TESTO [] |  Colonne mascherate  | 
|  funzioni\$1mascheramento  | TESTO [] |  Funzioni di mascheramento  | 
| peso | INT |  Peso della politica allegata  | 

# Funzioni di mascheramento dei dati predefinite
<a name="AuroraPostgreSQL.Security.DynamicMasking.PredefinedMaskingFunctions"></a>

`pg_columnmask`l'estensione fornisce funzioni di utilità integrate scritte in linguaggio C (per un'esecuzione più rapida) che possono essere utilizzate come espressione di mascheramento per le `pg_columnmask` politiche.

**mask\$1text**

Una funzione per mascherare i dati di testo con opzioni di visibilità configurabili.

**Arguments (Argomenti)**


| Parametro | DataType | Description | 
| --- | --- | --- | 
| input | TEXT |  La stringa di testo originale da mascherare  | 
| mask\$1char | CARATTERE (1) |  Carattere usato per mascherare (predefinito: 'X')  | 
| visible\$1prefix | INT |  Numero di caratteri all'inizio del testo di input che rimarranno non mascherati (impostazione predefinita: 0)  | 
| visible\$1suffix | INT |  Numero di caratteri alla fine del testo di input che rimarranno non mascherati (impostazione predefinita: 0)  | 
| use\$1hash\$1mask | BOOLEAN |  Se TRUE, utilizza un mascheramento basato su hash anziché mask\$1char (impostazione predefinita: FALSE)  | 

**Example di utilizzare diverse opzioni di mascheramento**  
Maschera l'intera stringa di input con il carattere 'X' predefinito  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World');
  mask_text  
-------------
 XXXXXXXXXXX
```
Usa l'`mask_char`argomento per mascherare l'immissione di testo utilizzando un carattere diverso  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*');
  mask_text  
-------------
 ***********
```
Usa `visible_prefix` i `visible_suffix` parametri per controllare quanti caratteri rimangono non mascherati all'inizio e alla fine del testo  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*', 5, 1);
  mask_text  
-------------
 Hello*****d
```
Quando `use_hash_mask` è vero, la stringa di input viene mascherata utilizzando caratteri casuali, l'`mask_char`argomento viene ignorato ma viene comunque `visible_prefix` rispettato `visible_suffix`  

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

**mask\$1timestamp**


| Parametro | DataType | Description | 
| --- | --- | --- | 
| ts\$1to\$1mask | TIMESTAMP |  Il timestamp originale da mascherare  | 
| mask\$1part | TEXT |  Speciifica quale parte del timestamp mascherare (impostazione predefinita: 'all') Valori validi: 'anno', 'mese', 'giorno', 'ora', 'minuto', 'secondo', 'tutto'  | 
| mask\$1value | TIMESTAMP |  Il valore del timestamp da usare per il mascheramento (predefinito: '1900-01-01 00:00:00 ')  | 

**Example di utilizzo di `mask_timestamps`**  
Questi esempi mostrano il mascheramento completo del timestamp su un valore predefinito, il mascheramento parziale di componenti del timestamp specifici (solo anno) e il mascheramento con un valore sostitutivo personalizzato.  
Maschera completamente il valore di input al timestamp predefinito  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00');
   mask_timestamp    
---------------------
 1900-01-01 00:00:00
```
Per mascherare solo una parte del timestamp, ad esempio solo l'anno  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00', 'year');
   mask_timestamp    
---------------------
 1900-06-15 14:30:00
```
Per modificare il valore mascherato per il timestamp usa l'argomento `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**

Una funzione per mascherare gli indirizzi e-mail preservando la struttura delle e-mail.


| Parametro | DataType | Description | 
| --- | --- | --- | 
| input | TEXT |  L'indirizzo email originale da mascherare  | 
| mask\$1char | CARATTERE (1) |  Carattere usato per mascherare (predefinito: 'X')  | 
| mask\$1local | BOOLEAN |  Se TRUE, maschera la parte locale dell'email (prima di @) (impostazione predefinita: TRUE)  | 
| mask\$1domain | BOOLEAN |  Se TRUE, maschera la parte del dominio dell'email (dopo @) (impostazione predefinita: TRUE)  | 

**Example di utilizzo di `mask_email`**  
Questi esempi illustrano il mascheramento completo delle e-mail, i caratteri di maschera personalizzati e il mascheramento selettivo della parte locale o della parte del dominio dell'indirizzo e-mail.  
Mascheratura completa  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com');
    mask_email    
------------------
 XXXX@XXXXXXX.com
```
Si usa `mask_char` per cambiare il carattere usato per mascherare  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*');
    mask_email    
------------------
 ****@*******.com
```
Usa `mask_local` e controlla `mask_domain` il mascheramento a livello locale e di dominio  

```
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
```

# Implementazione di pg\$1columnmask in un flusso di lavoro end-to-end
<a name="AuroraPostgreSQL.Security.DynamicMasking.WorkflowExample"></a>

Questa sezione illustra un'implementazione completa dell'`pg_columnmask`utilizzo di una tabella dei dipendenti di esempio con dati sensibili. Imparerai come creare funzioni di mascheramento personalizzate, definire più politiche di mascheramento con diversi livelli di peso per vari ruoli (stagista, supporto, analista) e osserverai come gli utenti con appartenenza a uno o più ruoli vedono diversi livelli di dati mascherati. Gli esempi riguardano anche il comportamento di mascheramento nelle istruzioni DML con clausole RETURNING, i trigger nelle tabelle rispetto alle viste e le operazioni di gestione delle politiche, tra cui la ridenominazione, la modifica dei pesi e la pulizia.

1. Crea una tabella di esempio con alcuni dati sensibili:

   ```
   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. Crea funzioni di mascheramento personalizzate:

   ```
   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. Crea più politiche con diversi livelli di mascheramento in base ai ruoli degli utenti:

   ```
   -- 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. Gli esempi seguenti mostrano come i diversi utenti visualizzano i dati in base all'appartenenza al ruolo e al peso delle politiche.

   ```
   -- 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;
   ```

   Come tirocinante (mascheramento più rigoroso):

   ```
   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
   ```

   Come utente di supporto (mascheramento moderato):

   ```
   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
   ```

   In qualità di analista (mascheramento più leggero):

   ```
   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
   ```

   Come utente ethan\$1support\$1intern che è sia stagista che utente di supporto:

   ```
   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
   ```

   Come john\$1analyst\$1intern che è sia stagista che analista:

   ```
   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
   ```

# Comprensione del comportamento di mascheramento nelle operazioni DML
<a name="AuroraPostgreSQL.Security.DynamicMasking.DMLMasking"></a>

`pg_columnmask`si applica in modo coerente a tutte le operazioni DML, incluse le istruzioni INSERT, UPDATE, DELETE e MERGE. Quando si eseguono queste operazioni, Aurora PostgreSQL maschera i dati secondo un principio fondamentale: tutti i dati letti dallo storage vengono mascherati in base alle policy applicabili dell'utente corrente.

Il mascheramento influisce su alcuni dei seguenti componenti di interrogazione, come:
+ Clausole WHERE
+ Condizioni JOIN
+ Sottoquery
+ Clausole di RESTITUZIONE

Tutti questi componenti funzionano su valori mascherati, non sui dati originali. Sebbene i dati vengano scritti nello storage senza mascherare, gli utenti vedono la loro visualizzazione mascherata solo quando li rileggono.

Aurora PostgreSQL applica tutti i vincoli del database (NOT NULL, UNIQUE, CHECK, FOREIGN KEY) sui valori effettivi memorizzati, non sui valori mascherati. Ciò può occasionalmente creare apparenti incongruenze se le funzioni di mascheramento non sono progettate con cura.

Il mascheramento funziona insieme alle autorizzazioni a livello di colonna:
+ Gli utenti senza privilegi SELECT non possono leggere le colonne
+ Gli utenti con privilegi SELECT vedono i valori mascherati in base alle politiche applicabili

# Comprensione del comportamento di mascheramento nelle funzioni di attivazione
<a name="AuroraPostgreSQL.Security.DynamicMasking.TriggerFunctionMasking"></a>

Quando `pg_columnmask` le policy vengono applicate alle tabelle, è importante capire come il mascheramento interagisce con le funzioni di attivazione. I trigger sono funzioni di database che vengono eseguite automaticamente in risposta a determinati eventi su una tabella, come le operazioni INSERT, UPDATE o DELETE.

Per impostazione predefinita, DDM applica regole di mascheramento diverse a seconda del tipo di trigger:

Trigger della tabella  
**Le tabelle di transizione sono smascherate**: le funzioni di attivazione sulle tabelle hanno accesso ai dati non mascherati nelle relative tabelle di transizione sia per le vecchie che per le nuove versioni di riga  
I proprietari delle tabelle creano i trigger e sono proprietari dei dati, in modo da avere pieno accesso per gestire le proprie tabelle in modo efficace

Visualizza i trigger (ANZICHÉ i trigger)  
**Le tabelle di transizione sono mascherate**: le funzioni di attivazione nelle viste visualizzano i dati mascherati in base alle autorizzazioni dell'utente corrente  
I proprietari delle viste possono differire dai proprietari delle tabelle di base e devono rispettare le politiche di mascheramento sulle tabelle sottostanti

Due parametri di configurazione a livello di server controllano il comportamento dei trigger con tabelle mascherate. Questi possono essere impostati solo da: `rds_superuser`
+ **Limita i trigger sulle tabelle mascherate**: impedisce l'esecuzione dei trigger quando un utente mascherato esegue operazioni DML su tabelle con politiche di mascheramento applicabili.
+ **Limita i trigger sulle viste con tabelle mascherate:** — Impedisce l'esecuzione dei trigger sulle viste quando la definizione della vista include tabelle con politiche di mascheramento applicabili all'utente corrente.

**Example delle differenze tra la funzione, l'applicazione, la tabella e la visualizzazione**  
L'esempio seguente crea una funzione di attivazione che stampa valori di riga vecchi e nuovi, quindi dimostra come la stessa funzione si comporti in modo diverso quando è collegata a una tabella rispetto a una vista.  

```
-- 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;
```
Consigliamo di esaminare il comportamento dei trigger prima di implementarli nelle tabelle mascherate. I trigger delle tabelle hanno accesso ai dati non mascherati nelle tabelle di transizione, mentre i trigger di visualizzazione visualizzano i dati mascherati.

**Example della politica di mascheramento della ridenominazione**  
L'esempio seguente mostra come rinominare le politiche esistenti utilizzando la procedura. `rename_masking_policy`  

```
-- 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 di alterare il peso delle politiche**  
L'esempio seguente mostra come modificare i pesi delle politiche per modificarne il peso.  

```
-- 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 di pulizia**  
L'esempio seguente mostra come eliminare tutte le politiche, le tabelle e gli utenti.  

```
-- 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;
```

# Configurazione del ruolo di gestione delle policy di mascheramento
<a name="AuroraPostgreSQL.Security.DynamicMasking.PolicyManagementRole"></a>

L'estensione `pg_columnmask` PostgreSQL per il mascheramento delle colonne consente di delegare la gestione delle policy di mascheramento a un ruolo specifico, anziché richiedere i privilegi del proprietario della tabella. `rds_superuser` Ciò fornisce un controllo più granulare su chi può creare, modificare ed eliminare le politiche di mascheramento.

Per configurare il ruolo che disporrà dei privilegi di gestione delle policy di mascheramento, procedi nel seguente modo:

1. Crea il ruolo di amministratore delle politiche: come utente`rds_superuser`, crea un nuovo ruolo responsabile della gestione delle politiche di mascheramento:

   ```
   CREATE ROLE mask_admin NOLOGIN;
   ```

1. Configura il parametro PostgreSQL: nel gruppo di parametri del cluster DB personalizzato, imposta il parametro di configurazione `pgcolumnmask.policy_admin_rolname` del motore sul nome del ruolo che hai creato:

   ```
   pgcolumnmask.policy_admin_rolname = mask_admin
   ```

   Questi parametri di configurazione del motore possono essere impostati in un gruppo di parametri del cluster DB e non richiede il riavvio dell'istanza. Per i dettagli sull'aggiornamento dei parametri, vedere[Modifica dei parametri in un gruppo di parametri del cluster DB in Amazon Aurora](USER_WorkingWithParamGroups.ModifyingCluster.md).

1. Concedi il ruolo agli utenti In quanto utente`rds_superuser`, concedi il `mask_admin` ruolo agli utenti che dovrebbero essere in grado di gestire le politiche di mascheramento:

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

   Inoltre, assicurati che gli utenti abbiano il privilegio USAGE sugli schemi in cui gestiranno le politiche di mascheramento:

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

Ora, quando gli utenti `alice` si `bob` connettono al database, possono utilizzare le funzioni di `pg_columnmask` estensione standard per creare, modificare ed eliminare le politiche di mascheramento su tutte le tabelle in tutti gli schemi in cui dispongono `USAGE` dei privilegi sullo schema.

# Le migliori pratiche per l'implementazione sicura di pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices"></a>

La sezione seguente fornisce le best practice di sicurezza per l'implementazione `pg_columnmask` nell'ambiente Aurora PostgreSQL. Segui questi consigli per:
+ Stabilisci un'architettura di controllo degli accessi sicura basata sui ruoli
+ Sviluppa funzioni di mascheramento che impediscano le vulnerabilità di sicurezza
+ Comprendi e controlla il comportamento dei trigger con dati mascherati

## Architettura di sicurezza basata sui ruoli
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.architecture"></a>

Definisci una gerarchia di ruoli per implementare i controlli di accesso nel tuo database. Aurora PostgreSQL `pg_columnmask` aumenta questi controlli fornendo un livello aggiuntivo per il mascheramento granulare dei dati all'interno di tali ruoli.

Crea ruoli dedicati in linea con le funzioni organizzative anziché concedere autorizzazioni ai singoli utenti. Questo approccio offre una migliore verificabilità e semplifica la gestione delle autorizzazioni man mano che la struttura organizzativa si evolve.

**Example di creare una gerarchia dei ruoli organizzativi**  
L'esempio seguente crea una gerarchia di ruoli organizzativi con ruoli dedicati per diverse funzioni, quindi assegna i singoli utenti ai ruoli appropriati. In questo esempio, i ruoli organizzativi (analyst\$1role, support\$1role) vengono creati per primi, quindi ai singoli utenti viene concessa l'appartenenza a questi ruoli. Questa struttura consente di gestire le autorizzazioni a livello di ruolo anziché per ogni singolo utente.  

```
-- 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;
```
Implementa il principio del privilegio minimo concedendo solo le autorizzazioni minime necessarie per ogni ruolo. Evita di concedere autorizzazioni ampie che potrebbero essere sfruttate se le credenziali vengono compromesse.  

```
-- 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;
```
Gli amministratori delle politiche richiedono `USAGE` privilegi sugli schemi in cui gestiscono le politiche di mascheramento. Concedi questi privilegi in modo selettivo, seguendo il principio del privilegio minimo. Effettua revisioni periodiche delle autorizzazioni di accesso allo schema per garantire che solo il personale autorizzato mantenga le capacità di gestione delle politiche.  
La configurazione dei parametri del ruolo di amministratore delle politiche è riservata ai soli amministratori del database. Questo parametro non può essere modificato a livello di database o di sessione, per evitare che gli utenti senza privilegi abbiano la precedenza sulle assegnazioni degli amministratori delle policy. Questa restrizione garantisce che il controllo delle policy di mascheramento rimanga centralizzato e sicuro.  
Assegna il ruolo di amministratore delle politiche a individui specifici anziché a gruppi. Questo approccio mirato garantisce un accesso selettivo alla gestione delle policy di mascheramento, in quanto gli amministratori delle policy hanno la possibilità di mascherare tutte le tabelle all'interno del database. 

## Sviluppo sicuro della funzione di mascheramento
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.MaskingDevelopment"></a>

Sviluppa funzioni di mascheramento utilizzando la semantica di associazione precoce per garantire il corretto tracciamento delle dipendenze e prevenire vulnerabilità di associazione tardiva, come la modifica del percorso di ricerca durante il runtime. Si consiglia di utilizzare la `BEGIN ATOMIC` sintassi per le funzioni SQL per abilitare la convalida in fase di compilazione (ovvero l'associazione anticipata) e la gestione delle dipendenze.

```
-- 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;
```

In alternativa, è possibile creare funzioni immuni alle modifiche del percorso di ricerca qualificando in modo esplicito lo schema di tutti i riferimenti agli oggetti, garantendo un comportamento coerente tra le diverse sessioni utente.

```
-- 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;
    $$;
```

Implementa la convalida degli input all'interno delle funzioni di mascheramento per gestire i casi limite e prevenire comportamenti imprevisti. Includi sempre la gestione dei NULL e convalida i formati di input per garantire un comportamento di mascheramento coerente. 

```
-- 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 attiva il comportamento con pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.DMLTriggerBehavior"></a>

Per i trigger delle tabelle, le tabelle di transizione verranno completamente smascherate. Per i trigger di visualizzazione (IOT), le tabelle di transizione verranno mascherate in base alle autorizzazioni di visualizzazione dell'utente corrente.

Trigger di tabella con pg\$1columnmask  
Ai trigger viene passata una tabella di transizione che contiene la vecchia e la nuova versione delle righe modificate dalla query DML di avvio. A seconda di quando viene attivato il trigger, Aurora PostgreSQL popola le righe vecchie e nuove. Ad esempio, un `BEFORE INSERT` trigger contiene solo nuove versioni delle righe e le vecchie versioni vuote perché non esiste una vecchia versione a cui fare riferimento.  
`pg_columnmask`non maschera le tabelle di transizione all'interno dei trigger delle tabelle. I trigger possono utilizzare colonne mascherate all'interno del loro corpo e vedono i dati non mascherati. Il creatore del trigger deve assicurarsi che il trigger venga eseguito per un utente. L'esempio seguente funziona correttamente in questo caso.  

```
-- 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;
```
Il creatore di Trigger comunica i dati non mascherati all'utente se non presta attenzione alle istruzioni che utilizza nel corpo del trigger. Ad esempio, l'utilizzo di a `RAISE NOTICE ‘%’, masked_column;` stampa la colonna per l'utente corrente.  

```
-- 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
```

Trigger sulle viste con pg\$1columnmask (anziché trigger)  
I trigger possono essere creati solo nelle viste in PostgreSQL. Vengono utilizzati per eseguire istruzioni DML su viste che non sono aggiornabili. Le tabelle di transito sono sempre mascherate all'interno anziché al trigger (IOT), poiché la vista e le tabelle di base utilizzate all'interno della query di visualizzazione potrebbero avere proprietari diversi. In tal caso, le tabelle di base potrebbero avere alcune politiche di mascheramento applicabili al proprietario della vista e il proprietario della vista deve sempre visualizzare i dati mascherati delle tabelle di base all'interno dei suoi trigger. Questo è diverso dai trigger sulle tabelle perché in tal caso il creatore del trigger e i dati all'interno delle tabelle sono di proprietà dello stesso utente, cosa che non avviene in questo caso.  

```
-- 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;
```

Livello GuCs di database/utente per controllare il comportamento dei trigger  
Due parametri di configurazione controllano il comportamento di esecuzione dei trigger per gli utenti con politiche di mascheramento applicabili. Utilizzate questi parametri per impedire l'esecuzione dei trigger su tabelle o viste mascherate quando sono necessarie restrizioni di sicurezza aggiuntive. Entrambi i parametri sono disabilitati per impostazione predefinita, per consentire ai trigger di essere eseguiti normalmente.  
**Primo GUC: restrizione di attivazione dei trigger sulle tabelle mascherate**  
Specifiche:  
+ Valore: `pgcolumnmask.restrict_dml_triggers_for_masked_users`
+ Tipo: `boolean`
+ Impostazione predefinita: `false` (i trigger possono essere eseguiti)
Impedisce l'esecuzione dei trigger sulle tabelle mascherate per gli utenti mascherati se impostata su TRUE. `pg_columnmask`esegue l'errore.  
**Secondo GUC: attiva la restrizione di attivazione delle viste con tabelle mascherate**  
Specifiche:  
+ Valore: `pgcolumnmask.restrict_iot_triggers_for_masked_users`
+ Tipo: `boolean`
+ Impostazione predefinita: `false` (i trigger possono essere eseguiti)
Impedisce l'esecuzione dei trigger nelle viste che includono tabelle mascherate nella loro definizione per gli utenti mascherati se impostata su TRUE.

Questi parametri funzionano in modo indipendente e sono configurabili come i parametri di configurazione standard del database.

# Scenari di spostamento dei dati in Aurora PostgreSQL pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement"></a>

`pg_columnmask`il comportamento varia tra le diverse operazioni di spostamento dei dati a seconda che l'operazione avvenga a livello di archiviazione, logico o applicativo. Le operazioni a livello di storage (come la clonazione) si comportano in modo diverso dalle operazioni logiche (ad esempio`pg_dump`) e dalle operazioni a livello di applicazione (come le query FDW). Questa sezione descrive il comportamento di mascheramento per scenari comuni, tra cui replica, backup, esportazioni e migrazioni, e spiega le implicazioni di sicurezza per ciascuno di essi.

**Topics**
+ [Database globale Aurora e repliche di lettura](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR)
+ [Duplicazione del database e ripristino delle istantanee](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones)
+ [Replica logica](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep)
+ [Implementazioni blu/verdi](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen)
+ [Stream Zero-ETL e CDC](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL)
+ [AWS Database Migration Service](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DMS)
+ [Esportazioni di dati](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport)
+ [Viste e viste materializzate](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views)
+ [Dump e ripristino dei dati](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR)
+ [Wrapper di dati esterni](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ)

## Database globale Aurora e repliche di lettura
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR"></a>

Le `pg_columnmask` policy Aurora sono archiviate nelle tabelle del sistema di database all'interno del volume del cluster. Tutte le repliche accedono alle stesse policy e restituiscono risultati mascherati in modo coerente. Per le implementazioni di Aurora Global Database, `pg_columnmask` le policy vengono replicate su tabelle secondarie Regioni AWS insieme ad altre tabelle di sistema di database, garantendo una protezione dei dati coerente in tutte le regioni. Durante gli scenari di failover, tutte le `pg_columnmask` policy rimangono intatte e funzionali.

## Duplicazione del database e ripristino delle istantanee
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones"></a>

Le operazioni di clonazione rapida e ripristino delle istantanee di Aurora preservano tutte le `pg_columnmask` policy, i ruoli e le configurazioni come parte delle tabelle del sistema di database. Il database clonato o ripristinato eredita tutte le politiche esistenti dal cluster di origine. Dopo la clonazione o il ripristino, ogni cluster di database mantiene politiche indipendenti. `pg_columnmask`

## Replica logica
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep"></a>

Durante la sincronizzazione iniziale, la replica logica utilizza operazioni SQL COPY standard e le `pg_columnmask` policy vengono applicate in base alle autorizzazioni dell'utente di replica. Durante il CDC (change data capture) in corso, le politiche di mascheramento non vengono applicate e i dati non mascherati vengono replicati tramite i record WAL. Gli utenti con `pg_create_subscription` privilegi possono potenzialmente esfiltrare i dati non mascherati impostando la replica su un sistema che controllano.

## Implementazioni blu/verdi
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen"></a>

Durante il ripristino delle istantanee, `pg_columnmask` le policy vengono incluse automaticamente. L'ambiente verde inizia con una copia identica di tutte le politiche dell'ambiente blu. Durante la replica dal blu al verde, i dati non vengono mascherati. Le successive modifiche alle policy di mascheramento (comandi DDL) sul cluster blu non vengono replicate sul cluster verde e invalidano le distribuzioni RDS. blue/green 

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

La replica dei dati non è influenzata dalle policy. `pg_columnmask` Zero-ETL supporta la replica DDL ma non replica o le policy RLS. `pg_columnmask` Nessuna policy di mascheramento viene applicata ai dati replicati in Zero-ETL.

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

La sincronizzazione iniziale dei dati viene mascherata o smascherata in base all'utente selezionato per l'attività DMS. I dati CDC vengono sempre smascherati. Sebbene le `pg_columnmask` relative politiche RLS interne possano essere migrate, non funzioneranno su target non abilitati per pg\$1columnmask.

## Esportazioni di dati
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport"></a>

`pg_columnmask`tratta le esportazioni come qualsiasi altra operazione di interrogazione: il mascheramento viene applicato in base alle autorizzazioni dell'utente che esegue l'esecuzione. Questo vale per comandi SQL come COPY, SELECT INTO, CREATE TABLE AS e la funzionalità di esportazione S3 di Aurora PostgreSQL. 

**Nota**  
Quando gli utenti mascherati esportano dati, i file risultanti contengono valori mascherati che possono violare i vincoli del database una volta ripristinati.

## Viste e viste materializzate
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views"></a>

Tieni a mente le seguenti considerazioni quando utilizzi le viste:
+ **Visualizzazioni normali**: utilizza sempre la `INVOKER` semantica. Le politiche di mascheramento dell'utente corrente si applicano quando si esegue una query sulla vista, indipendentemente da chi ha creato la vista.
+ **Viste materializzate**: quando vengono aggiornate, si applicano le politiche di mascheramento del proprietario della vista materializzata, non le politiche dell'utente che esegue l'aggiornamento. Se il proprietario ha delle politiche di mascheramento, la vista materializzata contiene sempre dati mascherati.

## Dump e ripristino dei dati
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR"></a>

`pg_dump`funziona come un normale utente del database e applica politiche di mascheramento basate sulle autorizzazioni dell'utente che si connette. Se un utente mascherato esegue un dump, il file di backup contiene dati mascherati. `pg_columnmask`le politiche sono incluse nel dump come parte dello schema del database. Il ripristino riuscito richiede che tutti i ruoli di riferimento siano presenti nel database di destinazione e che sulla destinazione sia installata l'`pg_columnmask`estensione.

**Nota**  
A partire da PostgreSQL 18`pg_dump`, supporta l'opzione che esclude sia `—no-policies` la Row Level Security (RLS) che le policy di mascheramento dai dump del database. `pg_columnmask` [Per ulteriori informazioni, consulta pg\$1dump.](https://www.postgresql.org/docs/current/app-pgdump.html)

## Wrapper di dati esterni
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ"></a>

Quando si utilizzano wrapper di dati esterni, i criteri di mascheramento sulle tabelle remote vengono applicati in base alle autorizzazioni dell'utente mappato sul server di origine, non alle autorizzazioni dell'utente che esegue le query locali e, sebbene sia possibile accedere ai dati remoti mascherati tramite FDW, non è possibile creare politiche DDM o RLS direttamente su tabelle esterne nel database locale.