

# Seguridad con Amazon Aurora PostgreSQL
<a name="AuroraPostgreSQL.Security"></a>

Para obtener información general de la seguridad de Aurora, consulte [Seguridad en Amazon Aurora](UsingWithRDS.md). Puede administrar la seguridad de Amazon Aurora PostgreSQL en varios niveles diferentes:
+ Utilice AWS Identity and Access Management (IAM) para controlar quién puede realizar acciones de administración de Amazon RDS en clústeres de base de datos e instancias de base de datos de Aurora PostgreSQL. IAM gestiona la autenticación de la identidad del usuario antes de que el usuario pueda acceder al servicio. También se encarga de la autorización, es decir, si el usuario puede hacer lo que está intentando hacer. La autenticación de bases de datos de IAM es un método de autenticación adicional que puede elegir al crear el clúster de base de datos Aurora PostgreSQL. Para obtener más información, consulte [Administración de la identidad y el acceso en Amazon Aurora](UsingWithRDS.IAM.md).

  Si utiliza IAM con el clúster de bases de datos de Aurora PostgreSQL, inicie sesión en la Consola de administración de AWS con sus credenciales de IAM primero, antes de abrir la consola de Amazon RDS en [https://console.aws.amazon.com/rds/](https://console.aws.amazon.com/rds/).
+ Asegúrese de crear clústeres de base de datos de Aurora en una nube privada virtual (VPC) basada en el servicio Amazon VPC. Utilice un grupo de seguridad de VPC para controlar qué dispositivos e instancias de Amazon EC2 pueden abrir conexiones con el punto de conexión y el puerto de la instancia de base de datos para los clústeres de base de datos de Aurora en una VPC. Puede realizar estas conexiones de puntos de conexión y puertos mediante el uso de capa de sockets seguros (SSL). Además, las reglas del firewall de su compañía pueden controlar si los dispositivos que se ejecutan en ella pueden abrir conexiones a una instancia de base de datos. Para obtener más información acerca de las VPC, consulte [VPC de Amazon y Amazon Aurora](USER_VPC.md).

  La tenencia de VPC admitida depende de la clase de instancia de base de datos que utilicen los clústeres de base de datos de Aurora PostgreSQL. En el caso de la tenencia de VPC `default`, el clúster de base de datos se ejecuta en hardware compartido. En el caso de la tenencia de una VPC `dedicated`, el clúster de base de datos se ejecuta en una instancia de hardware dedicada. Las clases de instancia de base de datos de rendimiento ampliable solo admiten el arrendamiento de VPC predeterminado. Las clases de instancia de base de datos de rendimiento ampliable incluyen las clases de instancia de base de datos db.t3 y db.t4g. Todas las demás clases de instancia de base de datos de Aurora PostgreSQL admiten la tenencia de VPC predeterminada y dedicada.

  Para obtener más información sobre las clases de instancias, consulte [Clases de instancia de base de datos de Amazon Aurora](Concepts.DBInstanceClass.md). Para obtener más información acerca de la tenencia de VPC `default` y `dedicated`, consulte [Instancias dedicadas](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/dedicated-instance.html) en la *Guía del usuario de Amazon Elastic Compute Cloud*.
+ Para conceder permisos a las bases de datos PostgreSQL que se ejecutan en el clúster de bases de datos Amazon Aurora, puede seguir el mismo procedimiento general que con las instancias independientes de PostgreSQL. Los comandos como `CREATE ROLE`, `ALTER ROLE`, `GRANT` y `REVOKE` funcionan de la misma forma que en las bases de datos en las instalaciones, al igual que la modificación directa de las tablas de los esquemas de las bases de datos.

  PostgreSQL administra los privilegios utilizando *roles*. El rol `rds_superuser` es el rol más privilegiado de un clúster de base de datos de Aurora PostgreSQL. Este rol se crea automáticamente y se otorga al usuario que crea el clúster de base de datos (la cuenta de usuario principal, `postgres` de forma predeterminada). Para obtener más información, consulte [Descripción de los roles y permisos de PostgreSQL](Appendix.PostgreSQL.CommonDBATasks.Roles.md). 

Todas las versiones de Aurora PostgreSQL, incluidas las versiones 10, 11, 12, 13, 14 y las versiones posteriores, admiten el mecanismo de autenticación mediante desafío-respuesta discontinuo (SCRAM) para las contraseñas como alternativa al resumen de mensajes (MD5). Le recomendamos que utilice SCRAM porque es más seguro que MD5. Para obtener más información, incluida la forma de migrar las contraseñas de los usuarios de base de datos de MD5 a SCRAM, consulte [Uso de SCRAM para el cifrado de contraseñas de PostgreSQL](PostgreSQL_Password_Encryption_configuration.md).

# Descripción de los roles y permisos de PostgreSQL
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles"></a>

Al crear un clúster de base de datos Aurora PostgreSQL utilizando la Consola de administración de AWS, se crea una cuenta de administrador al mismo tiempo. De forma predeterminada su nombre es `postgres`, tal y como se muestra en la siguiente captura de pantalla:

![\[La identidad de inicio de sesión predeterminada para las credenciales en la página Create database (Crear base de datos) es postgres.\]](http://docs.aws.amazon.com/es_es/AmazonRDS/latest/AuroraUserGuide/images/default-login-identity-apg-rpg.png)


Puede elegir otro nombre en lugar de aceptar el valor predeterminado (`postgres`). Si lo hace, el nombre que elija debe empezar por una letra y tener entre 1 y 16 caracteres alfanuméricos. Por simplicidad, nos referimos a esta cuenta de usuario principal por su valor predeterminado (`postgres`) en toda esta guía.

 Si utiliza `create-db-cluster` de la AWS CLI en lugar de la Consola de administración de AWS, crea el nombre de usuario pasándolo con el parámetro `master-username`. Para obtener más información, consulte [Paso 2: crear un clúster de base de datos de Aurora PostgreSQL](CHAP_GettingStartedAurora.AuroraPostgreSQL.FullConfig.md#CHAP_GettingStarted.AuroraPostgreSQL.CreateDBCluster).

Ya sea que utilice la Consola de administración de AWS, la AWS CLI o la API de Amazon RDS y si usa el nombre predeterminado `postgres` o elige otro nombre, esta primera cuenta de usuario de la base de datos es miembro del grupo `rds_superuser` y tiene `rds_superuser` privilegios.

**Topics**
+ [Descripción del rol rds\$1superuser](Appendix.PostgreSQL.CommonDBATasks.Roles.rds_superuser.md)
+ [Control del acceso de los usuarios a la base de datos de PostgreSQL](Appendix.PostgreSQL.CommonDBATasks.Access.md)
+ [Delegación y control de la administración de contraseñas de usuario](Appendix.PostgreSQL.CommonDBATasks.RestrictPasswordMgmt.md)
+ [Uso de SCRAM para el cifrado de contraseñas de PostgreSQL](PostgreSQL_Password_Encryption_configuration.md)

# Descripción del rol rds\$1superuser
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles.rds_superuser"></a>

En PostgreSQL, un *rol* puede definir un usuario, un grupo o un conjunto de permisos específicos concedidos a un grupo o usuario para varios objetos de la base de datos. Comandos de PostgreSQL para `CREATE USER` y `CREATE GROUP` se han sustituidos por los más generales, `CREATE ROLE` con propiedades específicas para distinguir a los usuarios de bases de datos. Un usuario de base de datos se puede concebir como un rol con el privilegio LOGIN. 

**nota**  
Los comandos `CREATE USER` y `CREATE GROUP` se pueden seguir utilizando. Para obtener más información, consulte [Roles de base de datos](https://www.postgresql.org/docs/current/user-manag.html) en la documentación de PostgreSQL.

El usuario `postgres` es el usuario de base de datos más privilegiado del clúster de base de datos Aurora PostgreSQL. Tiene las características definidas mediante la siguiente instrucción `CREATE ROLE`. 

```
CREATE ROLE postgres WITH LOGIN NOSUPERUSER INHERIT CREATEDB CREATEROLE NOREPLICATION VALID UNTIL 'infinity'
```

Las propiedades `NOSUPERUSER`, `NOREPLICATION`, `INHERIT` y `VALID UNTIL 'infinity'` son las opciones predeterminadas de CREATE ROLE, a menos que se especifique lo contrario. 

De forma predeterminada, `postgres` tiene privilegios otorgados al rol `rds_superuser` y permisos para crear roles y bases de datos. El rol `rds_superuser` permite al usuario `postgres` hacer lo siguiente: 
+ Añadir extensiones que estén disponibles para el uso con Aurora PostgreSQL. Para obtener más información, consulte [Uso de extensiones y contenedores de datos externos](Appendix.PostgreSQL.CommonDBATasks.md). 
+ Cree roles para los usuarios y conceder privilegios a los usuarios. Para obtener más información, consulte [CREATE ROLE](https://www.postgresql.org/docs/current/sql-createrole.html) y [GRANT](https://www.postgresql.org/docs/14/sql-grant.html) en la documentación de PostgreSQL. 
+ Creación de bases de datos Para obtener más información, consulte [CREATE DATABASE](https://www.postgresql.org/docs/14/sql-createdatabase.html) en la documentación de PostgreSQL.
+ Conceder privilegios de `rds_superuser` a los roles de usuario que no tengan estos privilegios y revocarlos según sea necesario. Le recomendamos que conceda este rol solo a los usuarios que realizan tareas de superusuario. En otras palabras, puede conceder este rol a los administradores de bases de datos (DBA) o a los administradores del sistema.
+ Conceda (y revoque) el rol `rds_replication` a usuarios de bases de datos que no tengan el rol `rds_superuser`. 
+ Conceder (y revocar) el rol `rds_password` a usuarios de bases de datos que no tengan el rol `rds_superuser`. 
+ Obtener información de estado sobre todas las conexiones de base de datos mediante la vista `pg_stat_activity`. Cuando sea necesario, `rds_superuser` puede detener cualquier conexión mediante `pg_terminate_backend` o `pg_cancel_backend`. 

En la instrucción `CREATE ROLE postgres...`, se puede ver que el rol de usuario `postgres` no permite específicamente permisos `superuser` de PostgreSQL. Aurora PostgreSQL es un servicio administrado, por lo que no puede acceder al sistema operativo host y no puede conectarse con la cuenta `superuser` de PostgreSQL. Muchas de las tareas que requieren acceso `superuser` en un PostgreSQL independiente se administra automáticamente mediante Aurora. 

Para obtener más información sobre la concesión de privilegios, consulte [GRANT](http://www.postgresql.org/docs/current/sql-grant.html) en la documentación de PostgreSQL.

El rol `rds_superuser` es uno de varios roles *predefinidos* en un clúster de base de datos de Aurora PostgreSQL. 

**nota**  
En PostgreSQL 13 y versiones anteriores, los roles *predefinidos* se denominan roles *predeterminados*.

En la siguiente lista encontrará algunos de los otros roles predefinidos que se crean automáticamente para un nuevo clúster de base de datos de Aurora PostgreSQL. Los roles predefinidos y sus privilegios no se pueden cambiar. No se pueden eliminar, cambiar de nombre ni modificar los privilegios de estos roles predefinidos. Intentar realizar una de estas operaciones producirá un error. 
+ **rds\$1password**: rol que puede cambiar las contraseñas y configurar restricciones de contraseña para los usuarios de bases de datos. Al rol `rds_superuser` se le otorga este rol de forma predeterminada y puede otorgarlo a los usuarios de la base de datos. Para obtener más información, consulte [Control del acceso de los usuarios a la base de datos de PostgreSQLControl del acceso de los usuarios a PostgreSQL](Appendix.PostgreSQL.CommonDBATasks.Access.md).
  + En las versiones de RDS para PostgreSQL anteriores a la 14, el rol `rds_password` puede cambiar las contraseñas y establecer restricciones de contraseña para los usuarios de la base de datos y los usuarios con el rol `rds_superuser`. A partir de la versión 14 de RDS para PostgreSQL, el rol `rds_password` puede cambiar las contraseñas y establecer restricciones de contraseña solo para los usuarios de la base de datos. Solo los usuarios con el rol `rds_superuser` pueden realizar estas acciones en otros usuarios con el rol `rds_superuser`. 
+ **rdsadmin**: rol creado para administrar muchas de las tareas de administración que el administrador con privilegios de `superuser` realizaría en una base de datos PostgreSQL independiente. Este rol lo utiliza internamente Aurora PostgreSQLpara muchas tareas de administración. 

# Visualización los de roles y sus privilegios
<a name="Appendix.PostgreSQL.CommonDBATasks.Roles.View"></a>

Puede ver los roles predefinidos y sus privilegios en la instancia de base de datos de RDS para PostgreSQL mediante distintos comandos en función de la versión de PostgreSQL. Para ver todos los roles predefinidos, puede conectarse a la instancia de base de datos de RDS para PostgreSQL y ejecutar los siguientes comandos con `psql`.

**Para `psql` 15 y versiones anteriores**

Conéctese a la instancia de base de datos de RDS para PostgreSQL y use el comando `\du` en psql:

```
postgres=> \du
                                                               List of roles
    Role name    |                         Attributes                         |                          Member of
-----------------+------------------------------------------------------------+------------------------------------------------------
 postgres        | Create role, Create DB                                    +| {rds_superuser}
                 | Password valid until infinity                              |
 rds_ad          | Cannot login                                               | {}
 rds_iam         | Cannot login                                               | {}
 rds_password    | Cannot login                                               | {}
 rds_replication | Cannot login                                               | {}
 rds_superuser   | Cannot login                                               | {pg_monitor,pg_signal_backend,rds_password,rds_replication}
 rdsadmin        | Superuser, Create role, Create DB, Replication, Bypass RLS+| {}
                 | Password valid until infinity                              |
```

**Para `psql` 16 y versiones posteriores**

```
postgres=> \drg+
                             List of role grants
   Role name   |          Member of          |       Options       | Grantor
---------------+-----------------------------+---------------------+----------
 postgres      | rds_superuser               | INHERIT, SET        | rdsadmin
 rds_superuser | pg_checkpoint               | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_monitor                  | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_signal_backend           | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | pg_use_reserved_connections | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | rds_password                | ADMIN, INHERIT, SET | rdsadmin
 rds_superuser | rds_replication             | ADMIN, INHERIT, SET | rdsadmin
```

Para comprobar la pertenencia al rol sin dependencia de versiones, puede utilizar la siguiente consulta SQL:

```
SELECT m.rolname AS "Role name", r.rolname AS "Member of"
FROM pg_catalog.pg_roles m
JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)
LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)
LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)
WHERE m.rolname !~ '^pg_'
ORDER BY 1, 2;
```

En la salida, puede ver que `rds_superuser` no es un rol de usuario de base de datos (no puede iniciar sesión), pero tiene los privilegios de muchos otros roles. También puede ver que el usuario de la base de datos `postgres` es miembro del rol `rds_superuser`. Como se ha mencionado anteriormente, `postgres` es el valor predeterminado de **Create database (Crear base de datos)** de la consola de Amazon RDS. Si ha elegido otro nombre, ese nombre se muestra en la lista de roles. 

**nota**  
 Las versiones 15.2 y 14.7 de Aurora PostgreSQL, introdujeron un comportamiento restrictivo del rol `rds_superuser`. Es necesario que al usuario de Aurora PostgreSQL se le conceda el privilegio `CONNECT` en la base de datos correspondiente para conectarse, incluso si se ha concedido al usuario el rol `rds_superuser`. Antes de las versiones 14.7 y 15.2 de Aurora PostgreSQL, un usuario podía conectarse a cualquier base de datos y tabla del sistema si se le concedía el rol `rds_superuser`. Este comportamiento restrictivo se alinea con los compromisos de AWS y Amazon Aurora de mejora continua de la seguridad.  
Actualice la lógica correspondiente de sus aplicaciones si la mejora anterior tiene alguna repercusión.

# Control del acceso de los usuarios a la base de datos de PostgreSQL
<a name="Appendix.PostgreSQL.CommonDBATasks.Access"></a>

Las nuevas bases de datos de PostgreSQL siempre se crean con un conjunto predeterminado de privilegios en el esquema `public` de la base de datos que permite a todos los usuarios y roles de la base de datos crear objetos. Estos privilegios permiten a los usuarios de la base de datos conectarse a la base de datos, or ejemplo, y crear tablas temporales mientras están conectados.

Para controlar mejor el acceso de los usuarios a las instancias de bases de datos que cree en el nodo principal del clúster de base de datos de Aurora PostgreSQL , le recomendamos que revoque estos privilegios de `public` predeterminados. Después de ello, conceda a continuación los privilegios específicos a los usuarios de base de datos de forma más detallada, como se muestra en el siguiente procedimiento. 

**Para configurar roles y privilegios para una nueva instancia de base de datos**

Supongamos que está configurando una base de datos en un clúster de base de datos Aurora PostgreSQL de reciente creación para que lo utilicen varios investigadores, todos los cuales necesitan acceso de lectura y escritura a la base de datos. 

1. Use `psql` (o pgAdmin) para conectarse a la instancia de base de datos principal de su clúster de base de datos de Aurora PostgreSQL 

   ```
   psql --host=your-cluster-instance-1.666666666666.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

   Escriba la contraseña cuando se le solicite. El cliente `psql` se conecta y muestra la base de datos de conexión administrativa predeterminada, `postgres=>`, como el símbolo del sistema.

1. Para evitar que los usuarios de la base de datos creen objetos en el esquema `public`, realice una de las siguientes opciones:

   ```
   postgres=> REVOKE CREATE ON SCHEMA public FROM PUBLIC;
   REVOKE
   ```

1. A continuación, cree una nueva instancia de base de datos:

   ```
   postgres=> CREATE DATABASE lab_db;
   CREATE DATABASE
   ```

1. Revoque todos los privilegios del esquema `PUBLIC` de esta nueva base de datos.

   ```
   postgres=> REVOKE ALL ON DATABASE lab_db FROM public;
   REVOKE
   ```

1. Cree un rol para los usuarios de bases de datos.

   ```
   postgres=> CREATE ROLE lab_tech;
   CREATE ROLE
   ```

1. Otorgue a los usuarios de bases de datos que tengan este rol la posibilidad de conectarse a la base de datos.

   ```
   postgres=> GRANT CONNECT ON DATABASE lab_db TO lab_tech;
   GRANT
   ```

1. Conceda a todos los usuarios que tengan el rol `lab_tech` todos los privilegios de esta base de datos.

   ```
   postgres=> GRANT ALL PRIVILEGES ON DATABASE lab_db TO lab_tech;
   GRANT
   ```

1. Cree usuarios de bases de datos de la siguiente manera:

   ```
   postgres=> CREATE ROLE lab_user1 LOGIN PASSWORD 'change_me';
   CREATE ROLE
   postgres=> CREATE ROLE lab_user2 LOGIN PASSWORD 'change_me';
   CREATE ROLE
   ```

1. Conceda a estos dos usuarios los privilegios asociados al rol lab\$1tech:

   ```
   postgres=> GRANT lab_tech TO lab_user1;
   GRANT ROLE
   postgres=> GRANT lab_tech TO lab_user2;
   GRANT ROLE
   ```

En este punto,`lab_user1` y `lab_user2` se pueden conectar a la base de datos de `lab_db`. En este ejemplo no se siguen las prácticas recomendadas para el uso empresarial, que pueden incluir la creación de varias instancias de base de datos, distintos esquemas y la concesión de permisos limitados. Para obtener más información y escenarios adicionales, consulte [Administración de usuarios y roles de PostgreSQL](https://aws.amazon.com/blogs//database/managing-postgresql-users-and-roles/). 

Para obtener más información sobre los privilegios en las bases de datos de PostgreSQL, consulte el comando [GRANT](https://www.postgresql.org/docs/current/static/sql-grant.html) en la documentación de PostgreSQL.

# Delegación y control de la administración de contraseñas de usuario
<a name="Appendix.PostgreSQL.CommonDBATasks.RestrictPasswordMgmt"></a>

Como DBA, es posible que desee delegar la administración de contraseñas de usuario. O bien, puede que desee evitar que los usuarios de la base de datos cambien sus contraseñas o reconfiguren las restricciones de contraseña, como la duración de la contraseña. Para asegurarse de que solo los usuarios de la base de datos que elija puedan cambiar la configuración de contraseñas, puede activar la función de administración de contraseñas restringidas. Cuando activa esta función, solo pueden administrar contraseñas aquellos usuarios de base de datos a los que se les haya concedido el rol `rds_password`. 

**nota**  
Para utilizar la administración de contraseñas restringida, su el clúster de base de datos de PostgreSQL Aurora debe estar ejecutando Amazon Aurora para 10.6 o una versión posterior.

De forma predeterminada, esta función es `off`, tal y como se muestra en el ejemplo siguiente:

```
postgres=> SHOW rds.restrict_password_commands;
  rds.restrict_password_commands
--------------------------------
 off
(1 row)
```

Para activar esta función, utilice un grupo de parámetros personalizado y cambie la configuración de `rds.restrict_password_commands` a 1. Asegúrese de reiniciar su Instancia de base de datos principal de Aurora PostgreSQL para que la configuración surta efecto. 

Con esta función activa, se necesitan privilegios de `rds_password` para los siguientes comandos SQL:

```
CREATE ROLE myrole WITH PASSWORD 'mypassword';
CREATE ROLE myrole WITH PASSWORD 'mypassword' VALID UNTIL '2023-01-01';
ALTER ROLE myrole WITH PASSWORD 'mypassword' VALID UNTIL '2023-01-01';
ALTER ROLE myrole WITH PASSWORD 'mypassword';
ALTER ROLE myrole VALID UNTIL '2023-01-01';
ALTER ROLE myrole RENAME TO myrole2;
```

Cambiar el nombre de un rol (`ALTER ROLE myrole RENAME TO newname`) también está restringido si la contraseña utiliza el algoritmo hash MD5. 

Con esta función activa, intentar cualquiera de estos comandos SQL sin los permisos de rol `rds_password`, genera el siguiente error: 

```
ERROR: must be a member of rds_password to alter passwords
```

Recomendamos que otorgar el `rds_password` solamente a unos cuantos roles que utilice únicamente para la administración de contraseñas. Si concede privilegios de `rds_password` a usuarios de bases de datos que no tengan privilegios de `rds_superuser`, también debe otorgarles el atributo `CREATEROLE`.

Asegúrese de que comprueba los requisitos de las contraseñas del lado del cliente, como el vencimiento y la complejidad necesaria. Si utiliza su propia utilidad del lado del cliente para cambios relacionados con la contraseña, la utilidad debe ser miembro de `rds_password` tener privilegios de `CREATE ROLE`. 

# Uso de SCRAM para el cifrado de contraseñas de PostgreSQL
<a name="PostgreSQL_Password_Encryption_configuration"></a>

El mecanismo de autenticación mediante *desafío-respuesta discontinuo (SCRAM)* es una alternativa al algoritmo de resumen de mensajes (MD5) predeterminado de PostgreSQL para cifrar contraseñas. El mecanismo de autenticación SCRAM se considera más seguro que MD5. Para obtener más información sobre estos dos enfoques diferentes para proteger las contraseñas, consulte [Password Authentication](https://www.postgresql.org/docs/14/auth-password.html) (Autenticación de contraseñas) en la documentación de PostgreSQL.

Le recomendamos que utilice SCRAM en lugar de MD5 como esquema de cifrado de contraseñas para su clúster de base de datos de Aurora PostgreSQL. SCRAM se admite en la versión 10 de Aurora PostgreSQL y en todas las versiones superiores, principales y secundarias. Es un mecanismo criptográfico de desafío-respuesta que utiliza el algoritmo scram-sha-256 algorithm para la autenticación y el cifrado de contraseñas. 

Es posible que deba actualizar las bibliotecas de las aplicaciones cliente para que sean compatibles con SCRAM. Por ejemplo, las versiones de JDBC anteriores a la 42.2.0 no admiten SCRAM. Para obtener más información, consulte [PostgreSQL JDBC Driver](https://jdbc.postgresql.org/changelogs/2018-01-17-42.2.0-release/) (Controlador JDBC de PostgreSQL) en la documentación del controlador JDBC de PostgreSQL. Para ver una lista de otros controladores de PostgreSQL y la compatibilidad con SCRAM, consulte [List of drivers](https://wiki.postgresql.org/wiki/List_of_drivers) (Lista de controladores) en la documentación de PostgreSQL.

Aurora PostgreSQL versión 14 y posteriores admite scram-sha-256 para el cifrado de contraseñas de forma predeterminada para los nuevos clústeres de base de datos. Para estas versiones, el grupo de parámetros del clúster de bases de datos predeterminado (`default.aurora-postgresql14`) tiene el valor de `password_encryption` establecido en scram-sha-256. No se admite en SCRAM para Aurora Serverless v1.

## Configuración del clúster de base de datos de Aurora PostgreSQL para que requiera SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.preliminary"></a>

Para Aurora PostgreSQL 14.3 y versiones posteriores, puede requerir que el clúster de Aurora PostgreSQL DB acepte únicamente contraseñas que utilicen el algoritmo scram-sha-256.

**importante**  
En el caso de los proxies RDS existentes con bases de datos de PostgreSQL, si modifica la autenticación de la base de datos para utilizar únicamente `SCRAM`, el proxy dejará de estar disponible durante un máximo de 60 segundos. Para evitar este problema, lleve a cabo alguna de las siguientes operaciones:  
Asegúrese de que la base de datos permita la autenticación `SCRAM` y `MD5`.
Para utilizar únicamente la autenticación `SCRAM`, cree un nuevo proxy, migre el tráfico de la aplicación al nuevo proxy y, a continuación, elimine el proxy previamente asociado a la base de datos.

Antes de realizar cambios en el sistema, asegúrese de entender el proceso completo, como se indica a continuación:
+ Obtenga información sobre todos los roles y el cifrado de las contraseñas de todos los usuarios de la base de datos. 
+ Compruebe de nuevo la configuración de los parámetros del clúster de base de datos de RDS para PostgreSQL correspondiente a los parámetros que controlan el cifrado de las contraseñas.
+ Si el clúster de base de datos de Aurora PostgreSQL utiliza un grupo de parámetros predeterminado, deberá crear un grupo de parámetros de clúster de base de datos personalizado y aplicarlo al clúster de base de datos de Aurora PostgreSQL para poder modificar los parámetros cuando sea necesario. Si el clúster de base de datos de Aurora PostgreSQL utiliza un grupo de parámetros personalizado, puede modificar los parámetros necesarios más adelante en el proceso, según sea necesario. 
+ Cambie el parámetro `password_encryption` por `scram-sha-256`.
+ Notifique a todos los usuarios de la base de datos que deben actualizar las contraseñas. Haga lo mismo con su cuenta de `postgres`. Las nuevas contraseñas se cifran y almacenan mediante el algoritmo scram-sha-256.
+ Verifique que todas las contraseñas están cifradas con el tipo de cifrado. 
+ Si todas las contraseñas utilizan scram-sha-256, puede cambiar el parámetro `rds.accepted_password_auth_method` de `md5+scram` a `scram-sha-256`. 

**aviso**  
Después de cambiar `rds.accepted_password_auth_method` a scram-sha-256 únicamente, no podrá conectarse ningún usuario (rol) con una contraseña cifrada con `md5`. 

### Preparación para requerir SCRAM para su clúster de bases de datos de Aurora PostgreSQL
<a name="PostgreSQL_Password_Encryption_configuration.getting-ready"></a>

Antes de realizar cambios en el clúster de base de datos de Aurora PostgreSQL , compruebe todas las cuentas de usuario de base de datos existentes. Compruebe también el tipo de cifrado utilizado para las contraseñas. Puede hacer estas tareas con la extensión `rds_tools`. Para ver qué versiones de PostgreSQL son compatibles con `rds_tools`, consulte [Versiones de extensión para Amazon RDS para PostgreSQL](https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html).

**Para obtener una lista de usuarios de base de datos (roles) y métodos de cifrado de contraseñas**

1. Use `psql` para conectarse a la instancia principal del clúster de base de datos de Aurora PostgreSQL , tal como se muestra a continuación.

   ```
   psql --host=cluster-name-instance-1.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

1. Instale la extensión de `rds_tools`.

   ```
   postgres=> CREATE EXTENSION rds_tools;
   CREATE EXTENSION
   ```

1. Obtenga una lista de los roles y el cifrado.

   ```
   postgres=> SELECT * FROM 
         rds_tools.role_password_encryption_type();
   ```

   Se muestra una salida similar a la siguiente.

   ```
          rolname        | encryption_type
   ----------------------+-----------------
    pg_monitor           |
    pg_read_all_settings |
    pg_read_all_stats    |
    pg_stat_scan_tables  |
    pg_signal_backend    |
    lab_tester           | md5
    user_465             | md5
    postgres             | md5
   (8 rows)
   ```

### Creación de un grupo de parámetros del clúster de base de datos personalizado
<a name="PostgreSQL_Password_Encryption_configuration.custom-parameter-group"></a>

**nota**  
Si el clúster de base de datos de RDS para Aurora PostgreSQL ya utiliza un grupo de parámetros personalizado, no necesita crear uno nuevo. 

Para obtener información general sobre los grupos de parámetros para Aurora, consulte [Creación de un grupo de parámetros de clúster de base de datos en Amazon Aurora](USER_WorkingWithParamGroups.CreatingCluster.md). 

El tipo de cifrado de contraseñas que se usa para las contraseñas se establece a un parámetro, `password_encryption`. El cifrado que permite el clúster de base de datos de Aurora PostgreSQL se establece a otro parámetro, `rds.accepted_password_auth_method`. Para cambiar cualquiera de los valores predeterminados, es necesario crear un grupo de parámetros de clúster de base de datos personalizado y aplicarlo al clúster . 

También puede utilizar la Consola de administración de AWS o la API de RDS para crear un grupo de parámetros de clúster de base de datos personalizado. Para obtener más información, consulte [Creación de un grupo de parámetros de clúster de base de datos en Amazon Aurora](USER_WorkingWithParamGroups.CreatingCluster.md). 

Ahora puede asociar el grupo de parámetros personalizado con su instancia de base de datos. 

**Para crear un grupo de parámetros del clúster de base de datosgrupo de parámetros de base de datos personalizado**

1. Utilice el comando `[create-db-cluster-parameter-group](https://docs.aws.amazon.com/cli/latest/reference/rds/create-db-cluster-parameter-group.html)` de la CLI para crear el grupo de parámetros personalizado para el clúster. En el siguiente ejemplo se utiliza `aurora-postgresql13` como origen de este grupo de parámetros personalizado. 

   Para Linux, macOS o Unix:

   ```
   aws rds create-db-cluster-parameter-group --db-cluster-parameter-group-name 'docs-lab-scram-passwords' \
     --db-parameter-group-family aurora-postgresql13  --description 'Custom DB cluster parameter group for SCRAM'
   ```

   Para Windows:

   ```
   aws rds create-db-cluster-parameter-group --db-cluster-parameter-group-name "docs-lab-scram-passwords" ^
     --db-parameter-group-family aurora-postgresql13  --description "Custom DB cluster parameter group for SCRAM"
   ```

   Ahora puede asociar el grupo de parámetros personalizado con el clúster. 

1. Utilice el comando `[modify-db-cluster](https://docs.aws.amazon.com/cli/latest/reference/rds/modify-db-cluster.html)` de la CLI para aplicar este grupo de parámetros personalizado al clúster de base de datos de Aurora PostgreSQL.

   Para Linux, macOS o Unix:

   ```
   aws rds modify-db-cluster --db-cluster-identifier 'your-instance-name' \
           --db-cluster-parameter-group-name "docs-lab-scram-passwords
   ```

   Para Windows:

   ```
   aws rds modify-db-cluster --db-cluster-identifier "your-instance-name" ^
           --db-cluster-parameter-group-name "docs-lab-scram-passwords
   ```

   Para volver a sincronizar el clúster de base de datos de Aurora PostgreSQL con el grupo de parámetros del clúster de base de datos personalizado, reinicie la instancia principal y todas las demás instancias del clúster. 

### Configuración del cifrado de contraseñas para utilizar SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.configure-password-encryption"></a>

El mecanismo de cifrado de contraseñas que utiliza un clúster de base de datos de Aurora PostgreSQL se establece en el grupo de parámetros de clúster de base de datos en el parámetro `password_encryption`. Los valores permitidos son: no establecido, `md5` o `scram-sha-256`. El valor predeterminado depende de la versión de Aurora PostgreSQL: del modo que se indica a continuación:
+ Aurora PostgreSQL 14: el valor predeterminado es `scram-sha-256`
+ Aurora PostgreSQL 13: el valor predeterminado es `md5`

Con un grupo de parámetros de clúster de base de datos personalizado adjuntado al clúster de base de datos de Aurora PostgreSQL, puede modificar los valores del parámetro de cifrado de contraseñas.

![\[A continuación, la consola de RDS muestra los valores predeterminados de los parámetros password_encryption de Aurora PostgreSQL.\]](http://docs.aws.amazon.com/es_es/AmazonRDS/latest/AuroraUserGuide/images/apg-pwd-encryption-md5-scram-1.png)


**Para cambiar la configuración de cifrado de contraseñas a scram-sha-256**
+ Cambie el valor del cifrado de contraseñas a scram-sha-256, como se muestra a continuación. El cambio se puede aplicar inmediatamente porque el parámetro es dinámico, por lo que no se requiere un reinicio para que el cambio surta efecto. 

  Para Linux, macOS o Unix:

  ```
  aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name \
    'docs-lab-scram-passwords' --parameters 'ParameterName=password_encryption,ParameterValue=scram-sha-256,ApplyMethod=immediate'
  ```

  Para Windows:

  ```
  aws rds modify-db-parameter-group --db-parameter-group-name ^
    "docs-lab-scram-passwords" --parameters "ParameterName=password_encryption,ParameterValue=scram-sha-256,ApplyMethod=immediate"
  ```

### Migración de las contraseñas de los roles de usuario a SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.migrating-users"></a>

Puede migrar las contraseñas de los roles de usuario a SCRAM, tal y como se describe a continuación.

**Para migrar las contraseñas de usuario (rol) de base de datos de MD5 a SCRAM**

1. Inicie sesión como usuario administrador (nombre de usuario predeterminado, `postgres`) como se muestra a continuación.

   ```
   psql --host=cluster-name-instance-1.111122223333.aws-region.rds.amazonaws.com --port=5432 --username=postgres --password
   ```

1. Compruebe la configuración del parámetro `password_encryption` en la instancia de base de datos de RDS para PostgreSQL con el siguiente comando.

   ```
   postgres=> SHOW password_encryption;
    password_encryption
   ---------------------
    md5
    (1 row)
   ```

1. Cambie el valor de este parámetro a scram-sha-256. Para obtener más información, consulte [Configuración del cifrado de contraseñas para utilizar SCRAM](#PostgreSQL_Password_Encryption_configuration.configure-password-encryption). 

1.  Compruebe de nuevo el valor para asegurarse de que ahora está establecido en `scram-sha-256`, como se indica a continuación. 

   ```
   postgres=> SHOW password_encryption;
    password_encryption
   ---------------------
    scram-sha-256
    (1 row)
   ```

1. Notifique a todos los usuarios de base de datos que deben cambiar la contraseña. Asegúrese de cambiar también su propia contraseña para la cuenta `postgres` (el usuario de base de datos con privilegios `rds_superuser`). 

   ```
   labdb=> ALTER ROLE postgres WITH LOGIN PASSWORD 'change_me';
   ALTER ROLE
   ```

1. Repita el proceso para todas las bases de datos del clúster de base de datos de Aurora PostgreSQL. 

### Cambio del parámetro para requerir SCRAM
<a name="PostgreSQL_Password_Encryption_configuration.require-scram"></a>

Este es el último paso del proceso. Después de realizar el cambio en el siguiente procedimiento, ninguna cuenta de usuario (rol) que aún utilice el cifrado `md5` para las contraseñas podrá iniciar sesión en el clúster de base de datos PostgreSQL de Aurora. 

Con `rds.accepted_password_auth_method` se especifica el método de cifrado que el clúster de base de datos de Aurora PostgreSQL acepta una contraseña de usuario durante el proceso de inicio de sesión. El valor predeterminado es `md5+scram`, lo que significa que se acepta cualquiera de los dos métodos. En la siguiente imagen, puede encontrar la configuración predeterminada de este parámetro.

![\[Consola de RDS con los valores predeterminados y permitidos para los parámetros rds.accepted_password_auth_method.\]](http://docs.aws.amazon.com/es_es/AmazonRDS/latest/AuroraUserGuide/images/pwd-encryption-md5-scram-2.png)


Los valores permitidos para este parámetro son:`md5+scram` o `scram` solo. El cambio de este valor de parámetro a `scram` lo convierte en un requisito. 

**Para cambiar el valor de parámetro para requerir la autenticación SCRAM para las contraseñas**

1. Verifique que todas las contraseñas de los usuarios de base de datos del clúster de base de datos de Aurora PostgreSQL utilizan `scram-sha-256` para el cifrado de contraseña. Para ello, consulte `rds_tools` para el rol (usuario) y el tipo de cifrado, de la siguiente manera. 

   ```
   postgres=> SELECT * FROM rds_tools.role_password_encryption_type();
     rolname        | encryption_type
     ----------------------+-----------------
     pg_monitor           |
     pg_read_all_settings |
     pg_read_all_stats    |
     pg_stat_scan_tables  |
     pg_signal_backend    |
     lab_tester           | scram-sha-256
     user_465             | scram-sha-256
     postgres             | scram-sha-256
     ( rows)
   ```

1. Repita la consulta en todas las instancias de base de datos del clúster de base de datos de Aurora PostgreSQL. 

   Si todas las contraseñas usan scram-sha-256, puede continuar. 

1. Cambie el valor de la autenticación de contraseña aceptada a scram-sha-256, como se indica a continuación.

   Para Linux, macOS o Unix:

   ```
   aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name 'docs-lab-scram-passwords' \
     --parameters 'ParameterName=rds.accepted_password_auth_method,ParameterValue=scram,ApplyMethod=immediate'
   ```

   Para Windows:

   ```
   aws rds modify-db-cluster-parameter-group --db-cluster-parameter-group-name "docs-lab-scram-passwords" ^
     --parameters "ParameterName=rds.accepted_password_auth_method,ParameterValue=scram,ApplyMethod=immediate"
   ```

## Protección de los datos de Aurora PostgreSQL con SSL/TLS
<a name="AuroraPostgreSQL.Security.SSL"></a>

Amazon RDS admite el cifrado mediante Capa de conexión segura (SSL) y Transport Layer Security (TLS) para los clústeres de base de datos de Aurora PostgreSQL. Con SSL/TLS, puede cifrar conexiones entre sus aplicaciones y sus clústeres de base de datos de Aurora PostgreSQL. También puede obligar a todas las conexiones con su clúster de base de datos de Aurora PostgreSQL a usar SSL/TLS. Amazon Aurora PostgreSQL admite Transport Layer Security (TLS), versiones 1.1 y 1.2. Se recomienda utilizar TLS 1.2 para conexiones cifradas. Se ha agregado compatibilidad con TLSv1.3 para las siguientes versiones de Aurora PostgreSQL:
+ Versión 15.3 y versiones posteriores
+ Versión 14.8 y versiones posteriores a la 14
+ Versión 13.11 y versiones posteriores a la 13
+ Versión 12.15 y versiones posteriores a la 12
+ Versión 11.20 y versiones posteriores a la 11

Para obtener la información general acerca de la compatibilidad con SSL/TLS y las bases de datos de PostgreSQL, consulte [Compatibilidad con SSL](https://www.postgresql.org/docs/current/libpq-ssl.html) en la documentación de PostgreSQL. Para obtener información sobre el uso de una conexión SSL/TLS a través de JDBC, consulte [Configuración del cliente](https://jdbc.postgresql.org/documentation/head/ssl-client.html) en la documentación de PostgreSQL.

**Topics**
+ [Requerir una conexión SSL/TLS a un clúster de base de datos de Aurora PostgreSQL](#AuroraPostgreSQL.Security.SSL.Requiring)
+ [Determinar el estado de la conexión SSL/TLS](#AuroraPostgreSQL.Security.SSL.Status)
+ [Configuración de conjuntos de cifrado para conexiones a clústeres de base de datos de Aurora PostgreSQL](#AuroraPostgreSQL.Security.SSL.ConfiguringCipherSuites)

La compatibilidad con SSL/TLS está disponible en todas las regiones de AWS para Aurora PostgreSQL. Amazon RDS crea un certificado SSL/TLS destinado al clúster de base de datos de Aurora PostgreSQL cuando se crea el clúster de base de datos. Si se habilita la verificación con certificado SSL/TLS, el certificado incluye el punto de enlace del clúster de base de datos como nombre común (CN) que el certificado de SSL/TLS debe proteger frente a los ataques de suplantación. 

**Para conectar con un clúster de base de datos de Aurora PostgreSQL a través de SSL/TLS**

1. Descargue el certificado.

   Para obtener más información acerca de cómo descargar certificados, consulte [Uso de SSL/TLS para cifrar una conexión a un clúster de base de datos](UsingWithRDS.SSL.md).

1. Importe el certificado en su sistema operativo.

1. Conéctese a su clúster de base de datos de Aurora PostgreSQL a través de SSL/TLS.

   Cuando se conecte mediante SSL/TLS, su cliente podrá elegir verificar la cadena de certificados o no. Si sus parámetros de conexión especifican `sslmode=verify-ca` o `sslmode=verify-full`, su cliente precisa que los certificados de CA de RDS estén en su almacén de confianza o se haga referencia a ellos en la URL de conexión. Este requisito es para verificar la cadena de certificados que firma su certificado de base de datos.

   Cuando un cliente, como psql o JDBC, está configurado con soporte de SSL/TLS, primero el cliente intenta conectarse a la base de datos con SSL/TLS de forma predeterminada. Si el cliente no puede conectarse mediante SSL/TLS, vuelve a la conexión sin SSL/TLS. De forma predeterminada, la opción `sslmode` para los clientes basados en JDBC y libpq está establecida en `prefer`. 

   Use el parámetro `sslrootcert` para hacer referencia al certificado, por ejemplo: `sslrootcert=rds-ssl-ca-cert.pem`.

A continuación, aparece un ejemplo de cómo usar psql para conectarse a un clúster de base de datos de Aurora PostgreSQL.

```
$ psql -h testpg.cdhmuqifdpib.us-east-1.rds.amazonaws.com -p 5432 \
    "dbname=testpg user=testuser sslrootcert=rds-ca-2015-root.pem sslmode=verify-full"
```

### Requerir una conexión SSL/TLS a un clúster de base de datos de Aurora PostgreSQL
<a name="AuroraPostgreSQL.Security.SSL.Requiring"></a>

Para exigir conexiones SSL/TLS al clúster de base de datos de Aurora PostgreSQL, use el parámetro `rds.force_ssl`.
+ Para requerir conexiones SSL/TLS, establezca el valor del parámetro `rds.force_ssl` en 1 (activado).
+ Para desactivar las conexiones SSL/TLS requeridas, establezca el valor del parámetro `rds.force_ssl` en 0 (desactivado).

El valor predeterminado de este parámetro depende de la versión de Aurora PostgreSQL:
+ Para las versiones 17 y posteriores de Aurora PostgreSQL: el valor predeterminado es 1 (activado).
+ Para las versiones 16 y más antiguas de Aurora PostgreSQL: el valor predeterminado es 0 (desactivado).

**nota**  
Cuando realiza una actualización de versión principal de Aurora PostgreSQL versión 16 o anterior a la versión 17 o posterior, el valor predeterminado del parámetro cambia de 0 (desactivado) a 1 (activado). Este cambio puede provocar errores de conectividad en las aplicaciones que no estén configuradas para SSL. Puede volver al comportamiento predeterminado anterior estableciendo este parámetro en 0 (desactivado).

Para obtener más información acerca de la gestión de parámetros, consulte [Grupos de parámetros para Amazon Aurora](USER_WorkingWithParamGroups.md).

Al actualizar el parámetro `rds.force_ssl`, se define también el parámetro `ssl` de PostgreSQL como 1 (activado) y se modifica el archivo `pg_hba.conf` del clúster de base de datos para permitir la nueva configuración de SSL/TLS.

Cuando el parámetro `rds.force_ssl` se haya definido en 1 para un clúster de base de datos, al conectarse verá una salida similar a la siguiente, que indica que ahora se requiere SSL/TLS:

```
$ psql postgres -h SOMEHOST.amazonaws.com -p 8192 -U someuser
psql (9.3.12, server 9.4.4)
WARNING: psql major version 9.3, server major version 9.4.
Some psql features might not work.
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

postgres=>
```

### Determinar el estado de la conexión SSL/TLS
<a name="AuroraPostgreSQL.Security.SSL.Status"></a>

El estado cifrado de su conexión se muestra en el banner de inicio de sesión al establecer conexión con el clúster de base de datos.

```
Password for user master: 
psql (9.3.12) 
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256) 
Type "help" for help.   

postgres=>
```

También puede cargar la extensión `sslinfo` y llamar después a la función `ssl_is_used()` para determinar si se está utilizando SSL/TLS. La función devuelve `t` si la conexión usa SSL/TLS; de lo contrario, devuelve `f`.

```
postgres=> create extension sslinfo;
CREATE EXTENSION

postgres=> select ssl_is_used();
 ssl_is_used
---------
t
(1 row)
```

Puede utilizar el comando `select ssl_cipher()` para determinar el cifrado SSL/TLS:

```
postgres=> select ssl_cipher();
ssl_cipher
--------------------
DHE-RSA-AES256-SHA
(1 row)
```

 Si habilita `set rds.force_ssl` y reinicia el clúster de la base de datos, las conexiones que no usen SSL se rechazarán con el siguiente mensaje:

```
$ export PGSSLMODE=disable
$ psql postgres -h SOMEHOST.amazonaws.com -p 8192 -U someuser
psql: FATAL: no pg_hba.conf entry for host "host.ip", user "someuser", database "postgres", SSL off
$
```

Para obtener información acerca de la opción `sslmode`, consulte [Funciones de control de conexión de la base de datos](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) en la documentación de PostgreSQL.

### Configuración de conjuntos de cifrado para conexiones a clústeres de base de datos de Aurora PostgreSQL
<a name="AuroraPostgreSQL.Security.SSL.ConfiguringCipherSuites"></a>

Mediante el uso de conjuntos de cifrado configurables, puede tener más control sobre la seguridad de las conexiones de su base de datos. Puede especificar una lista de conjuntos de cifrado que desea permitir para proteger las conexiones SSL/TLS del cliente a su base de datos. Con conjuntos de cifrado configurables, puede controlar el cifrado de conexión que acepta el servidor de base de datos. Esto ayuda a evitar el uso de cifrados inseguros o obsoletos.

Los conjuntos de cifrado configurables son compatibles con las versiones 11.8 y posteriores de Aurora PostgreSQL.

Con el fin de especificar la lista de cifrados permitidos para cifrar conexiones, modifique el parámetro del clúster `ssl_ciphers`. Establezca el parámetro `ssl_ciphers` en una cadena de valores de cifrado separados por comas en un grupo de parámetros de clúster mediante la Consola de administración de AWS, la AWS CLI o la API de RDS. Para configurar los parámetros de clúster, consulte [Modificación de los parámetros en un grupo de parámetros de clúster de base de datos en Amazon Aurora](USER_WorkingWithParamGroups.ModifyingCluster.md).

En la tabla siguiente, se muestran los cifrados compatibles para las versiones de motor válidas de Aurora PostgreSQL.


| Versiones del motor de Aurora PostgreSQL | Cifrados compatibles | TLS 1.1 | TLS 1.2 | TLS 1.3 | 
| --- | --- | --- | --- | --- | 
| 9.6, 10.20 y versiones anteriores, 11.15 versiones anteriores, 12.10 versiones anteriores, 13.6 versiones anteriores | DHE-RSA-AES128-SHA DHE-RSA-AES128-SHA256 DHE-RSA-AES128-GCM-SHA256 DHE-RSA-AES256-SHA DHE-RSA-AES256-SHA256 DHE-RSA-AES256-GCM-SHA384 ECDHE-ECDSA-AES256-SHA ECDHE-ECDSA-AES256-GCM-SHA384 ECDHE-RSA-AES256-SHA384 ECDHE-RSA-AES128-SHA ECDHE-RSA-AES128-SHA256 ECDHE-RSA-AES128-GCM-SHA256 ECDHE-RSA-AES256-SHA ECDHE-RSA-AES256-GCM-SHA384 | Sí No No No No No Sí No No Sí No No Sí No | No Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí |  No No No No No No No No No No No No No No  | 
| 10.21, 11.16, 12.11, 13.7, 14.3 y 14.4 |  ECDHE-RSA-AES128-SHATLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 | Sí No Sí No Sí No Sí No No Sí No Sí No | Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí | No No No No No No No No No No No No No | 
| 10.22, 11.17, 12.12, 13.8, 14.5 y 15.2 |  TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 |  Sí No No Sí No Sí No No Sí No No Sí No Sí Sí No  | Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí | No No No No No No No No No No No No No No No No | 
| 11.20, 12.15, 13.11, 14.8, 15.3, 16.1 y versiones posteriores | TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1GCM\$1SHA384 TLS\$1RSA\$1WITH\$1AES\$1256\$1CBC\$1SHA TLS\$1RSA\$1WITH\$1AES\$1128\$1GCM\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA256 TLS\$1RSA\$1WITH\$1AES\$1128\$1CBC\$1SHA TLS\$1ECDHE\$1RSA\$1WITH\$1CHACHA20\$1POLY1305\$1SHA256 TLS\$1AES\$1128\$1GCM\$1SHA256 TLS\$1AES\$1256\$1GCM\$1SHA384  | Sí No No Sí No Sí No No Sí No No Sí No Sí Sí No No No | Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí Sí No No |  No No No No No No No No No No No No No No No No Sí Sí  | 

También puede utilizar el comando de la CLI [describe-motor-default-cluster-parameters](https://docs.aws.amazon.com/cli/latest/reference/rds/describe-engine-default-cluster-parameters.html) para determinar qué conjuntos de cifrado se admiten actualmente para una familia de grupos de parámetros específica. El siguiente ejemplo muestra cómo obtener los valores permitidos para el parámetro `ssl_cipher` de clúster para Aurora PostgreSQL 11.

```
aws rds describe-engine-default-cluster-parameters --db-parameter-group-family aurora-postgresql11
                
    ...some output truncated...
	{
		"ParameterName": "ssl_ciphers",
		"Description": "Sets the list of allowed TLS ciphers to be used on secure connections.",
		"Source": "engine-default",
		"ApplyType": "dynamic",
		"DataType": "list",
		"AllowedValues": "DHE-RSA-AES128-SHA,DHE-RSA-AES128-SHA256,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-AES256-SHA,DHE-RSA-AES256-SHA256,DHE-RSA-AES256-GCM-SHA384,
		ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES128-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-RSA-AES256-SHA,ECDHE-RSA-AES256-SHA384,ECDHE-RSA-AES256-GCM-SHA384,TLS_RSA_WITH_AES_256_GCM_SHA384,
		TLS_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
		TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
		"IsModifiable": true,
		"MinimumEngineVersion": "11.8",
		"SupportedEngineModes": [
			"provisioned"
		]
	},
    ...some output truncated...
```

El parámetro `ssl_ciphers` se establece de forma predeterminada en todos los conjuntos de cifrado permitidos. Para obtener más información sobre los cifrados, consulte la variable [ssl\$1ciphers](https://www.postgresql.org/docs/current/runtime-config-connection.html#GUC-SSL-CIPHERS) en la documentación de PostgreSQL. 

# Uso del enmascaramiento dinámico con Aurora PostgreSQL
<a name="AuroraPostgreSQL.Security.DynamicMasking"></a>

El enmascaramiento de datos dinámico es una característica de seguridad que protege la información confidencial de las bases de datos de Aurora PostgreSQL al controlar la forma en que los usuarios ven los datos en el momento de la consulta. Aurora lo implementa a través de la extensión `pg_columnmask`. `pg_columnmask` proporciona una protección de datos por columna que complementa los mecanismos nativos de control de acceso granular y de seguridad por fila de PostgreSQL.

Con `pg_columnmask`, puede crear políticas de enmascaramiento que determinan la visibilidad de los datos en función de los roles de los usuarios. Cuando los usuarios consultan tablas con políticas de enmascaramiento, Aurora PostgreSQL aplica la función de enmascaramiento adecuada en el momento de la consulta en función del rol del usuario y del peso de la política. Los datos subyacentes permanecen sin cambios en el almacenamiento.

`pg_columnmask` admite las siguientes capacidades:
+ **Funciones de enmascaramiento integradas y personalizadas**: utilice funciones prediseñadas para patrones comunes, como el enmascaramiento del correo electrónico y el texto, o cree sus propias funciones personalizadas para proteger la información confidencial (PII) mediante políticas de enmascaramiento basadas en SQL.
+ **Múltiples estrategias de enmascaramiento**: oculte completamente la información, sustituya valores parciales por caracteres comodín o defina enfoques de enmascaramiento personalizados.
+ **Priorización de políticas**: defina varias políticas para una sola columna. Use ponderaciones para determinar qué política de enmascaramiento debe usarse cuando se apliquen varias políticas a una columna. Aurora PostgreSQL aplica políticas según el peso y la pertenencia a los roles de usuario. 

`pg_columnmask` está disponible en la versión 16.10 y superior de Aurora PostgreSQL y en la versión 17.6 y superior. Está disponible sin costo adicional.

# Introducción al enmascaramiento dinámico
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted"></a>

Para enmascarar los datos de forma dinámica, debe instalar la extensión `pg_columnmask` en la base de datos y crear políticas de enmascaramiento para las tablas. El proceso de configuración implica la verificación de los requisitos previos, la instalación de la extensión, la configuración de los roles, la creación de políticas y las pruebas de validación.

## Instalación y configuración de la extensión
<a name="AuroraPostgreSQL.Security.DynamicMasking.GetStarted.Installation"></a>

Conéctese al clúster de Aurora PostgreSQL mediante el editor de consultas de la consola de RDS o un cliente de PostgreSQL, como psql, con las credenciales de rds\$1superuser (usuario maestro).

Ejecute el comando de creación de extensiones para habilitar la funcionalidad `pg_columnmask`:

```
CREATE EXTENSION pg_columnmask;
```

Este comando instala la extensión `pg_columnmask`, crea las tablas de catálogo necesarias y registra las funciones de enmascaramiento integradas. La instalación de la extensión es específica de la base de datos, lo que significa que debe instalarla de forma independiente en cada base de datos en la que se requiera la funcionalidad.

**nota**  
Las conexiones realizadas antes de instalar esta extensión seguirán mostrando los datos desenmascarados. Ciérrela y vuelva a conectarla para solucionar este problema.

Verifique la instalación de la extensión comprobando las funciones de enmascaramiento disponibles:

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

# Procedimientos para administrar políticas de enmascaramiento de datos
<a name="AuroraPostgreSQL.Security.DynamicMasking.Procedures"></a>

Puede administrar las políticas de enmascaramiento mediante los procedimientos proporcionados por la extensión `pg_columnmask`. Para crear, modificar o eliminar políticas de enmascaramiento, debe contar con uno de los siguientes privilegios:
+ Propietario de la tabla en la que va a crear la política de `pg_columnmask`.
+ Miembro de `rds_superuser`.
+ Miembro del rol de mánager de la política de `pg_columnmask` establecido por el parámetro `pgcolumnmask.policy_admin_rolname`.

El siguiente comando crea una tabla que se utiliza en las siguientes secciones:

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

El siguiente procedimiento crea una nueva política de enmascaramiento para una tabla de usuarios:

**Sintaxis**

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

**Argumentos**


| Parámetro | Tipo de datos | Descripción | 
| --- | --- | --- | 
| policy\$1name | NAME |  Nombre de la política de enmascaramiento. Debe ser único por tabla.  | 
| table\$1name | REGCLASS |  El nombre cualificado o no cualificado o nulo de la tabla para aplicar la política de enmascaramiento.  | 
| masking\$1expressions | JSONB |  Objeto JSON que contiene los pares de nombre de columna y función de enmascaramiento. Cada clave es el nombre de una columna y su valor es la expresión de enmascaramiento que se va a aplicar a esa columna.  | 
| roles | NAME[] |  Los roles a los que se aplica esta política de enmascaramiento. Predeterminado es PUBLIC.  | 
| weight | INT |  Peso de la política de enmascaramiento. Cuando se apliquen varias políticas a la consulta de un usuario determinado, la política con el peso más alto (número entero más alto) se aplicará a cada columna enmascarada. El valor predeterminado es 0. No hay dos políticas de enmascaramiento de la tabla que puedan tener el mismo peso.  | 

**Tipo de devolución**

Ninguno

**Example de crear una política de enmascaramiento que oculte la columna de correo electrónico del rol `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>

Este procedimiento modifica una política de enmascaramiento existente. `ALTER_MASKING_POLICY` puede modificar las expresiones de enmascaramiento de la política, el conjunto de roles a los que se aplica la política y el peso de la política de enmascaramiento. Cuando se omite uno de esos parámetros, la parte correspondiente de la política permanece inalterada.

**Sintaxis**

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

**Argumentos**


| Parámetro | Tipo de datos | Descripción | 
| --- | --- | --- | 
| policy\$1name | NAME |  El nombre existente de la política de enmascaramiento.  | 
| table\$1name | REGCLASS |  El nombre cualificado o no cualificado o nulo de la tabla que contiene la política de enmascaramiento.  | 
| masking\$1expressions | JSONB |  Nuevo objeto JSON que contiene los pares de nombre de columna y función de enmascaramiento, de lo contrario, NULL.  | 
| roles | NAME[] |  La lista de roles nuevos a los que se aplica esta política de enmascaramiento o NULL en caso contrario.  | 
| weight | INT |  Nuevo peso para la política de enmascaramiento o NULL en caso contrario.  | 

**Tipo de devolución**

Ninguno

**Example de agregar el rol de analista a una política de enmascaramiento existente sin cambiar otros atributos de la política.**  

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

Este procedimiento elimina una política de enmascaramiento existente.

**Sintaxis**

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

**Argumentos**


| Parámetro | Tipo de datos | Descripción | 
| --- | --- | --- | 
| policy\$1name | NAME |  El nombre existente de la política de enmascaramiento.  | 
| table\$1name | REGCLASS |  El nombre cualificado o no cualificado o nulo de la tabla que contiene la política de enmascaramiento.  | 

**Tipo de devolución**

Ninguno

**Example de eliminar la política de enmascaramiento customer\$1mask**  

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

# Identificadores de escape en el procedimiento de DDL de la política de enmascaramiento
<a name="AuroraPostgreSQL.Security.DynamicMasking.EscapeIdentifiers"></a>

Al crear políticas de enmascaramiento de datos con los identificadores entre comillas, es necesario utilizarlas adecuadamente para garantizar que las referencias a los objetos y la aplicación de la política sean correctas. Para utilizar los identificadores entre comillas en los procedimientos de administración de la política de enmascaramiento `pg_columnmask`:
+ **Nombre de la política**: debe estar entre comillas dobles.
+ **Nombre de la tabla**: el nombre del esquema y el nombre de la tabla deben escribirse entre comillas dobles de forma individual cuando sea necesario.
+ **Expresiones de enmascaramiento**: los nombres de las columnas y funciones de las expresiones de enmascaramiento deben ir entre comillas dobles y las propias comillas deben ir precedidas de una barra invertida.
+ **Roles**: la matriz de nombres de roles se cita automáticamente. El nombre del rol debe coincidir exactamente con el nombre que se muestra en `pg_roles` al distinguir mayúsculas y minúsculas.

**Example de la sintaxis de escape y comillas**  
En este ejemplo, se muestra la sintaxis de escape y comillas adecuada al crear políticas de enmascaramiento para tablas, columnas, funciones y roles que utilizan nombres en mayúsculas y minúsculas o que requieren identificadores entre comillas en 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
```

## Vistas administrativas
<a name="AuroraPostgreSQL.Security.DynamicMasking.AdminViews"></a>

Puede revisar toda la política de `pg_columnmask` mediante la vista administrativa de `pgcolumnmask.pg_columnmask_policies` de acceso público. La siguiente información está disponible mediante esta vista. La vista solo devuelve las políticas de enmascaramiento que son propiedad del usuario actual.


| Nombre de la columna | Tipo de datos: | Descripción | 
| --- | --- | --- | 
|  schemaname  | NAME |  Esquema de la relación a la que está asociada la política  | 
|  tablename  | NAME |  Nombre de la relación a la que está asociada la política  | 
|  policyname  | NAME |  Nombre de la política de enmascaramiento, todas las políticas de enmascaramiento tienen nombres únicos  | 
|  roles  | TEXT[] |  Rol al que se aplica la política.  | 
|  masked\$1columns  | TEXT[] |  Columnas de enmascaramiento  | 
|  masking\$1functions  | TEXT[] |  Funciones de enmascaramiento  | 
| weight | INT |  Peso de la política adjunta  | 

# Funciones de enmascaramiento de datos predefinidas
<a name="AuroraPostgreSQL.Security.DynamicMasking.PredefinedMaskingFunctions"></a>

La extensión `pg_columnmask` proporciona funciones de utilidad integradas escritas en lenguaje C (para una ejecución más rápida) que se pueden utilizar como expresión de enmascaramiento para las políticas de `pg_columnmask`.

**mask\$1text**

Una función para enmascarar datos de texto con opciones de visibilidad configurables.

**Argumentos**


| Parámetro | Tipo de datos | Descripción | 
| --- | --- | --- | 
| input | TEXT |  La cadena de texto original que se va a enmascarar  | 
| mask\$1char | CHAR (1) |  Carácter utilizado para enmascarar (predeterminado: “X”)  | 
| visible\$1prefix | INT |  Número de caracteres al principio del texto ingresado que permanecerán desenmascarados (predeterminado: 0)  | 
| visible\$1suffix | INT |  Número de caracteres al final del texto ingresado que permanecerán desenmascarados (predeterminado: 0)  | 
| use\$1hash\$1mask | BOOLEANO |  Si es TRUE, utiliza un enmascaramiento basado en hash en lugar de mask\$1char (predeterminado: FALSE)  | 

**Example de usar diferentes opciones de enmascaramiento**  
Enmascaramiento de toda la cadena de entrada con el carácter “X” predeterminado  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World');
  mask_text  
-------------
 XXXXXXXXXXX
```
Uso del argumento `mask_char` para enmascarar la entrada de texto con un carácter diferente  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*');
  mask_text  
-------------
 ***********
```
Uso de los parámetros `visible_prefix` y `visible_suffix` para controlar el número de caracteres que permanecen desenmascarados al principio y al final del texto  

```
postgres=> SELECT pgcolumnmask.mask_text('Hello World', '*', 5, 1);
  mask_text  
-------------
 Hello*****d
```
Cuando `use_hash_mask` es verdadero, la cadena de entrada está enmascarada con caracteres aleatorios, el argumento `mask_char` se ignora pero se sigue respetando `visible_prefix` y `visible_suffix`  

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

**mask\$1timestamp**


| Parámetro | Tipo de datos | Descripción | 
| --- | --- | --- | 
| ts\$1to\$1mask | TIMESTAMP |  La marca temporal original que se va a enmascarar  | 
| mask\$1part | TEXT |  Especifica qué parte de la marca temporal se debe enmascarar (predeterminado: “todas”) Valores válidos: “año”, “mes”, “día”, “hora”, “minuto”, “segundo”, “todo”  | 
| mask\$1value | TIMESTAMP |  El valor de la marca de tiempo que se va a usar para enmascarar (predeterminado: “1900-01-01 00:00:00”)  | 

**Example de cómo usar `mask_timestamps`**  
Estos ejemplos muestran el enmascaramiento completo de la marca de tiempo con un valor predeterminado, el enmascaramiento parcial de componentes específicos de la marca de tiempo (solo en el año) y el enmascaramiento con un valor de reemplazo personalizado.  
Enmascaramiento completo del valor de entrada con la marca de tiempo predeterminada  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00');
   mask_timestamp    
---------------------
 1900-01-01 00:00:00
```
Enmascaramiento solo de una parte de la marca de tiempo, por ejemplo, solo el año  

```
postgres=> SELECT pgcolumnmask.mask_timestamp('2023-06-15 14:30:00', 'year');
   mask_timestamp    
---------------------
 1900-06-15 14:30:00
```
Cambio del valor enmascarado de la marca de tiempo mediante el argumento `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 función para enmascarar las direcciones de correo electrónico y, al mismo tiempo, preservar la estructura del correo electrónico.


| Parámetro | Tipo de datos | Descripción | 
| --- | --- | --- | 
| input | TEXT |  La dirección de correo electrónico original que se va a enmascarar  | 
| mask\$1char | CHAR (1) |  Carácter utilizado para enmascarar (predeterminado: “X”)  | 
| mask\$1local | BOOLEANO |  Si es TRUE, enmascara la parte local del correo electrónico (antes de @) (predeterminado: TRUE)  | 
| mask\$1domain | BOOLEANO |  Si es TRUE, enmascara la parte de dominio del correo electrónico (después de @) (predeterminado: TRUE)  | 

**Example de cómo usar `mask_email`**  
Estos ejemplos muestran el enmascaramiento completo del correo electrónico, los caracteres de máscara personalizados y el enmascaramiento selectivo de la parte local o de la parte del dominio de la dirección de correo electrónico.  
Enmascaramiento completo  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com');
    mask_email    
------------------
 XXXX@XXXXXXX.com
```
Uso de `mask_char` para cambiar el carácter utilizado para enmascarar  

```
postgres=> SELECT pgcolumnmask.mask_email('user@example.com', '*');
    mask_email    
------------------
 ****@*******.com
```
Uso de `mask_local` y `mask_domain` para controlar el enmascaramiento en el entorno local y en el 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
```

# Implementación de pg\$1columnmask en un flujo de trabajo integral
<a name="AuroraPostgreSQL.Security.DynamicMasking.WorkflowExample"></a>

En esta sección se muestra una implementación completa del `pg_columnmask` mediante el uso de un ejemplo de tabla de empleados con información confidencial. Obtendrá información sobre cómo crear funciones de enmascaramiento personalizadas, definir múltiples políticas de enmascaramiento con diferentes niveles de peso para roles diferentes (pasante, de soporte, analista) y a observar cómo los usuarios que pertenecen a uno o varios roles ven diferentes niveles de datos enmascarados. Los ejemplos también incluyen el comportamiento de enmascaramiento en las instrucciones DML con cláusulas RETURNING, los activadores que utilizan tablas frente a vistas y las operaciones de administración de políticas, como el cambio de nombre, la modificación de los pesos y la limpieza.

1. Cree una tabla de ejemplo con información confidencial:

   ```
   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. Cree funciones de enmascaramiento personalizadas:

   ```
   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. Cree varias políticas con diferentes niveles de enmascaramiento en función de los roles de los usuarios:

   ```
   -- 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. Los siguientes ejemplos muestran cómo los diferentes usuarios ven los datos en función de la pertenencia a un rol y los pesos de las políticas.

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

   Como pasante (enmascaramiento más estricto):

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

   Como usuario de apoyo (enmascaramiento moderado):

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

   Como analista (el enmascaramiento más ligero):

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

   Como usuario ethan\$1support\$1intern, que es a la vez pasante y usuario de soporte:

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

   Como john\$1analyst\$1intern, que es a la vez pasante y 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
   ```

# Comprensión del comportamiento de enmascaramiento en las operaciones de DML
<a name="AuroraPostgreSQL.Security.DynamicMasking.DMLMasking"></a>

`pg_columnmask` se aplica de forma coherente en todas las operaciones de DML, como las instrucciones INSERT, UPDATE, DELETE y MERGE. Al ejecutar estas operaciones, Aurora PostgreSQL enmascara los datos de acuerdo con un principio fundamental: todos los datos leídos del almacenamiento se enmascaran de acuerdo con las políticas aplicables del usuario actual.

El enmascaramiento afecta a algunos de los siguientes componentes de la consulta, como:
+ cláusulas WHERE
+ condiciones de JOIN
+ subconsultas
+ cláusulas RETURNING

Todos estos componentes funcionan con valores enmascarados, no con los datos originales. Aunque los datos se escriben en el almacenamiento desenmascarado, los usuarios solo ven su vista enmascarada cuando los vuelven a leer.

Aurora PostgreSQL aplica todas las restricciones de la base de datos (NOT NULL, UNIQUE, CHECK, FOREIGN KEY) a los valores almacenados reales, no a los valores enmascarados. En ocasiones, esto puede crear aparentes incoherencias si las funciones de enmascaramiento no se diseñan cuidadosamente.

El enmascaramiento trabaja junto con los permisos por columnas:
+ Los usuarios sin privilegios SELECT no pueden leer las columnas
+ Los usuarios con privilegios SELECT ven los valores enmascarados de acuerdo con las políticas aplicables

# Comprensión del comportamiento de enmascaramiento en las funciones de activación
<a name="AuroraPostgreSQL.Security.DynamicMasking.TriggerFunctionMasking"></a>

Cuando se aplican políticas de `pg_columnmask` a las tablas, es importante entender cómo interactúa el enmascaramiento con las funciones de activación. Los activadores son funciones de la base de datos que se ejecutan automáticamente en respuesta a determinados eventos de una tabla, como las operaciones INSERT, UPDATE o DELETE.

De forma predeterminada, DDM aplica diferentes reglas de enmascaramiento según el tipo de activador:

Activadores de tablas  
**Las tablas de transición están desenmascaradas**: las funciones activadoras de las tablas tienen acceso a los datos desenmascarados de sus tablas de transición en las versiones de filas antiguas y en las nuevas  
Los propietarios de las tablas crean los activadores y son dueños de los datos, por lo que tienen acceso total para administrar sus tablas de manera eficaz

Consulta de activadores (EN LUGAR DE los activadores)  
**Las tablas de transición están enmascaradas**: las funciones de activación de las vistas ven los datos enmascarados según los permisos del usuario actual  
Los propietarios de las vistas pueden diferir de los propietarios de la tabla base y deben respetar las políticas de enmascaramiento de las tablas subyacentes

Dos parámetros de configuración por servidor controlan el comportamiento de los activadores con tablas enmascaradas. Estos solo se pueden configurar mediante `rds_superuser`:
+ **Restringir los activadores en las tablas enmascaradas**: impide la ejecución de los activadores cuando un usuario enmascarado realiza operaciones de DML en tablas con las políticas de enmascaramiento aplicables.
+ **Restringir los activadores en las vistas con tablas enmascaradas:** impide la ejecución de los activadores en las vistas cuando la definición de la vista incluye tablas con políticas de enmascaramiento aplicables al usuario actual.

**Example de las diferencias entre la aplicación de la función a la tabla y la vista**  
El siguiente ejemplo crea una función de activación que imprime los valores de fila antiguos y nuevos y, a continuación, demuestra cómo la misma función se comporta de forma diferente cuando se adjunta a una tabla y no 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;
```
Se recomienda revisar el comportamiento de los activadores antes de implementarlos en las tablas enmascaradas. Los activadores de tablas tienen acceso a los datos desenmascarados de las tablas de transición, mientras que los activadores de visualización ven los datos enmascarados.

**Example de cambio de nombre de la política de enmascaramiento**  
En el siguiente ejemplo se muestra cómo cambiar el nombre de las políticas existentes mediante el procedimiento `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 de modificar el peso de las políticas**  
En el siguiente ejemplo se muestra cómo modificar las ponderaciones de las políticas para cambiar su 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 de limpieza**  
En el siguiente ejemplo se muestra cómo eliminar todas las políticas, tablas y usuarios.  

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

# Configuración del rol de administración de políticas de enmascaramiento
<a name="AuroraPostgreSQL.Security.DynamicMasking.PolicyManagementRole"></a>

La extensión de enmascaramiento de columnas de PostgreSQL, `pg_columnmask`, le permite delegar la administración de las políticas de enmascaramiento a un rol específico, en lugar de requerir privilegios de propietario de tablas o `rds_superuser`. Esto proporciona un control más detallado sobre quién puede crear, modificar y eliminar las políticas de enmascaramiento.

Para configurar el rol que tendrá privilegios de administración de políticas de enmascaramiento, siga estos pasos:

1. Cree el rol de administrador de políticas: como un `rds_superuser`, cree un nuevo rol responsable de administrar las políticas de enmascaramiento:

   ```
   CREATE ROLE mask_admin NOLOGIN;
   ```

1. Configure el parámetro PostgreSQL: en el grupo de parámetros de clúster de base de datos personalizado, defina el parámetro de configuración del motor de `pgcolumnmask.policy_admin_rolname` con el nombre del rol que creó:

   ```
   pgcolumnmask.policy_admin_rolname = mask_admin
   ```

   Estos parámetros de configuración del motor se pueden establecer en un grupo de parámetros de un clúster de base de datos y no requiere el reinicio de la instancia. Para obtener más información sobre la actualización del parámetro, consulte [Modificación de los parámetros en un grupo de parámetros de clúster de base de datos en Amazon Aurora](USER_WorkingWithParamGroups.ModifyingCluster.md).

1. Otorgue el rol a los usuarios Como `rds_superuser`, conceda el rol de `mask_admin` a los usuarios que deberían administrar las políticas de enmascaramiento:

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

   Además, asegúrese de que los usuarios tengan el privilegio de USO en los esquemas en los que administrarán las políticas de enmascaramiento:

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

Ahora, cuando los usuarios `alice` y `bob` se conecten a la base de datos, podrán utilizar las funciones de extensión estándar `pg_columnmask` para crear, modificar y eliminar políticas de enmascaramiento en todas las tablas de todos los esquemas en los que tengan privilegios `USAGE` en el esquema.

# Prácticas recomendadas para la implementación segura de pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices"></a>

En la siguiente sección, se proporcionan las prácticas recomendadas de seguridad para la implementación de `pg_columnmask` en el entorno de Aurora PostgreSQL. Siga estas recomendaciones para:
+ Establecimiento de una arquitectura de control de acceso basada en roles segura
+ Desarrollo de funciones de enmascaramiento que eviten las vulnerabilidades de seguridad
+ Comprensión y control del comportamiento de los activadores con datos enmascarados

## Arquitectura de seguridad basada en roles
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.architecture"></a>

Defina una jerarquía de roles para implementar controles de acceso en la base de datos. Aurora PostgreSQL `pg_columnmask` amplía estos controles al proporcionar una capa adicional para el enmascaramiento de datos detallado dentro de esos roles.

Cree roles dedicados que se alineen con funciones organizativas en lugar de conceder permisos a usuarios individuales. Este enfoque proporciona una mejor auditoría y simplifica la administración de permisos a medida que la estructura organizativa evoluciona.

**Example de creación de una jerarquía de roles organizativos**  
En el siguiente ejemplo, se crea una jerarquía de roles organizativos con roles específicos para distintas funciones y, a continuación, se asignan usuarios individuales a los roles correspondientes. En este ejemplo, primero se crean los roles organizativos (analyst\$1role, support\$1role) y, a continuación, se concede a los usuarios individuales la pertenencia a estos roles. Esta estructura le permite administrar los permisos por rol y no para cada usuario individual.  

```
-- 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;
```
Implemente el principio de privilegio mínimo mediante la concesión de solo los permisos mínimos necesarios para cada rol. Evite conceder permisos amplios que puedan aprovecharse si las credenciales se ven comprometidas.  

```
-- 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;
```
Los administradores de políticas requieren privilegios de `USAGE` en los esquemas en los que administran las políticas de enmascaramiento. Conceda estos privilegios de forma selectiva, siguiendo el principio de privilegio mínimo. Realice revisiones periódicas de los permisos de acceso al esquema para asegurarse de que solo el personal autorizado mantenga las capacidades de administración de políticas.  
La configuración de los parámetros del rol de administrador de políticas está restringida solo a los administradores de bases de datos. Este parámetro no se puede modificar en la base de datos o sesión, lo que impide que los usuarios sin privilegios invaliden las asignaciones de administradores de políticas. Esta restricción garantiza que el control de la política de enmascaramiento permanezca centralizado y seguro.  
Asigne el rol de administrador de políticas a individuos específicos en lugar de a grupos. Este enfoque específico garantiza el acceso selectivo a la administración de políticas de enmascaramiento, ya que los administradores de políticas tienen la capacidad de enmascarar todas las tablas de la base de datos. 

## Desarrollo seguro de la función de enmascaramiento
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.MaskingDevelopment"></a>

Desarrolle funciones de enmascaramiento utilizando una semántica de enlace temprana para garantizar un seguimiento adecuado de las dependencias y evitar vulnerabilidades de enlace tardío, como la modificación de la ruta de búsqueda durante el tiempo de ejecución. Se recomienda utilizar la sintaxis `BEGIN ATOMIC` de las funciones de SQL para permitir la validación en tiempo de compilación (es decir, la vinculación temprana) y la administración de las dependencias.

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

Como alternativa, cree funciones que sean inmunes a los cambios en la ruta de búsqueda mediante un esquema explícito que califique todas las referencias a los objetos para garantizar un comportamiento coherente en las distintas sesiones de usuario.

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

Implemente la validación de entradas en las funciones de enmascaramiento para gestionar los casos de periferia y evitar comportamientos inesperados. Incluya siempre el manejo NULL y valide los formatos de entrada para garantizar un comportamiento de enmascaramiento coherente. 

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

## Comportamiento de activadores de DML con pg\$1columnmask
<a name="AuroraPostgreSQL.Security.DynamicMasking.BestPractices.DMLTriggerBehavior"></a>

Para los activadores de tablas, las tablas de transición se desenmascararán por completo. Para los activadores de visualización (IOT), las tablas de transición se enmascararán de acuerdo con los permisos de visualización del usuario actual.

Activadores de tablas con pg\$1columnmask  
A los activadores se les pasa una tabla de transición que contiene la versión antigua y la nueva de las filas modificadas por la consulta de DML de activación. Según el momento en que se active el activador, Aurora PostgreSQL rellena las filas antiguas y nuevas. Por ejemplo, un activador `BEFORE INSERT` solo tiene versiones nuevas de las filas y versiones antiguas vacías porque no hay ninguna versión anterior a la que hacer referencia.  
`pg_columnmask` no enmascara las tablas de transición dentro de los activadores de las tablas. Los activadores pueden usar columnas enmascaradas dentro de su cuerpo y ve los datos desenmascarados. El creador del activador debe asegurarse de cómo se ejecuta el activador para un usuario. El siguiente ejemplo funciona correctamente en este 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;
```
El creador del activador filtra datos desenmascarados al usuario si no tiene cuidado con las instrucciones que utiliza en el cuerpo del activador. Por ejemplo, el uso de `RAISE NOTICE ‘%’, masked_column;` imprime la columna al usuario actual.  

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

Se activa en las vistas con pg\$1columnmask (en lugar de activadores)  
Los activadores solo se pueden crear en las vistas de PostgreSQL. Se utilizan para ejecutar instrucciones DML en vistas que no se pueden actualizar. Las tablas de tránsito siempre están enmascaradas en el interior en lugar de activarlas (IOT), ya que la vista y las tablas base utilizadas dentro de la consulta de vista pueden tener propietarios diferentes. En ese caso, las tablas base pueden tener algunas políticas de enmascaramiento aplicables al propietario de la vista y el propietario de la vista siempre debe ver los datos enmascarados de las tablas base dentro de sus activadores. Esto es diferente de los activadores de las tablas porque, en ese caso, el creador del activador y los datos contenidos en las tablas son propiedad del mismo usuario, lo que no es el caso aquí.  

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

Los GUC por base de datos o usuario para controlar el comportamiento de los activadores  
Dos parámetros de configuración controlan el comportamiento de ejecución de los activadores para los usuarios con políticas de enmascaramiento aplicables. Utilice estos parámetros para evitar que los activadores se ejecuten en tablas o vistas enmascaradas cuando se requieran restricciones de seguridad adicionales. Ambos parámetros están desactivados de forma predeterminada, lo que permite que los activadores se ejecuten con normalidad.  
**Primer GUC: desencadene la restricción de activación en tablas enmascaradas**  
Especificaciones:  
+ Nombre: `pgcolumnmask.restrict_dml_triggers_for_masked_users`
+ Tipo: `boolean`
+ Predeterminado: `false` (se permite la ejecución de los activadores)
Impide la ejecución del activador en tablas enmascaradas para los usuarios enmascarados cuando se establece en TRUE. `pg_columnmask` corrige el error.  
**Segundo GUC: desencadene la restricción de activación en vistas con tablas enmascaradas**  
Especificaciones:  
+ Nombre: `pgcolumnmask.restrict_iot_triggers_for_masked_users`
+ Tipo: `boolean`
+ Predeterminado: `false` (se permite la ejecución de los activadores)
Impide la ejecución del activador en vistas que incluyen tablas enmascaradas en su definición para los usuarios enmascarados cuando se establece en TRUE.

Estos parámetros funcionan de forma independiente y se pueden configurar como los parámetros de configuración de una base de datos estándar.

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

El comportamiento `pg_columnmask` varía según las distintas operaciones de movimiento de datos en función de si la operación se produce en la capa de almacenamiento, lógica o aplicación. Las operaciones por almacenamiento (como la clonación) se comportan de manera diferente a las operaciones lógicas (como `pg_dump`) y las operaciones por aplicación (como las consultas de FDW). En esta sección se describe el comportamiento de enmascaramiento en escenarios comunes, como la replicación, las copias de seguridad, las exportaciones y las migraciones, y se explican las implicaciones de seguridad de cada uno de ellos.

**Topics**
+ [Base de datos global de Aurora y réplicas de lectura](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR)
+ [Restauración de copias e instantáneas de bases de datos](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones)
+ [Replicación lógica](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep)
+ [Implementaciones azul/verde](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen)
+ [Transmisiones zero-ETL y CDC](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL)
+ [AWS Database Migration Service](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DMS)
+ [Exportaciones de datos](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport)
+ [Vistas y vistas materializadas](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views)
+ [Volcado y restauración de datos](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR)
+ [Contenedor de datos externos](#AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ)

## Base de datos global de Aurora y réplicas de lectura
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.RR"></a>

Las políticas de `pg_columnmask` de Aurora se almacenan en tablas del sistema de bases de datos dentro del volumen del clúster. Todas las réplicas acceden a las mismas políticas y devuelven resultados enmascarados de forma coherente. Para las implementaciones de Aurora Global Database, las políticas de `pg_columnmask` se replican en Regiones de AWS secundarias junto con otras tablas del sistema de bases de datos, lo que garantiza una protección de datos coherente en todas las regiones. Durante los escenarios de conmutación por error, todas las políticas de `pg_columnmask` permanecen intactas y funcionales.

## Restauración de copias e instantáneas de bases de datos
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Clones"></a>

Las operaciones de restauración de instantáneas y clonación rápida de Aurora conservan todas las políticas de `pg_columnmask`, roles y configuraciones como parte de las tablas del sistema de bases de datos. La base de datos clonada o restaurada hereda todas las políticas existentes del clúster de origen. Tras la clonación o la restauración, cada clúster de base de datos mantiene políticas de `pg_columnmask` independientes.

## Replicación lógica
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.LogRep"></a>

Durante la sincronización inicial, la replicación lógica utiliza operaciones estándar de SQL COPY y las políticas de `pg_columnmask` se aplican en función de los permisos del usuario de la replicación. Durante el CDC continuo (captura de datos de cambio), no se aplican políticas de enmascaramiento y los datos desenmascarados se replican a través de los registros de WAL. Los usuarios con privilegios de `pg_create_subscription` pueden filtrar datos desenmascarados configurando la replicación en un sistema que controlen.

## Implementaciones azul/verde
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.BlueGreen"></a>

Durante la restauración de las instantáneas, las políticas de `pg_columnmask` se incluyen automáticamente. El entorno verde comienza con una copia idéntica de todas las políticas del entorno azul. Durante la replicación, de azul a verde, los datos no se enmascaran. Los cambios posteriores en la política de enmascaramiento (comandos DDL) en el clúster azul no se replican en el clúster verde e invalidan las implementaciones azul/verde de RDS.

## Transmisiones zero-ETL y CDC
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.ZETL"></a>

La replicación de datos no se ve afectada por las políticas de `pg_columnmask`. Zero-ETL admite la replicación de DDL, pero no replica `pg_columnmask` ni las políticas de RLS. No se aplican políticas de enmascaramiento a los datos replicados en Zero-ETL.

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

La sincronización de datos inicial se enmascara o desenmascara en función del usuario seleccionado para la tarea de DMS. Los datos de CDC siempre están desenmascarados. Aunque las políticas de RLS internas relacionadas con `pg_columnmask` se pueden migrar, no funcionarán en destinos non-pg\$1columnmask-enabled.

## Exportaciones de datos
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DataExport"></a>

`pg_columnmask` trata las exportaciones como cualquier otra operación de consulta: el enmascaramiento se aplica en función de los permisos del usuario ejecutor. Esto se aplica a los comandos de SQL como COPY, SELECT INTO, CREATE TABLE AS y a la funcionalidad de exportación de S3 de Aurora PostgreSQL. 

**nota**  
Cuando los usuarios enmascarados exportan datos, los archivos resultantes contienen valores enmascarados que, al restaurarse, pueden infringir las restricciones de la base de datos.

## Vistas y vistas materializadas
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.Views"></a>

Tenga en cuenta las siguientes consideraciones al utilizar las vistas:
+ **Vistas normales**: utilice siempre la semántica de `INVOKER`. Las políticas de enmascaramiento del usuario actual se aplican al consultar la vista, independientemente de quién la haya creado.
+ **Vistas materializadas**: cuando se actualizan, se aplican las políticas de enmascaramiento del propietario de la vista materializada, no las políticas del usuario que realiza la actualización. Si el propietario tiene políticas de enmascaramiento, la vista materializada siempre contiene datos enmascarados.

## Volcado y restauración de datos
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.DDR"></a>

`pg_dump` funciona como un usuario normal de la base de datos y aplica políticas de enmascaramiento en función de los permisos del usuario que se conecta. Si un usuario enmascarado realiza un volcado, el archivo de copia de seguridad contiene datos enmascarados. Las políticas de `pg_columnmask` se incluyen en el volcado como parte del esquema de la base de datos. La restauración correcta requiere que todos los roles a los que se hace referencia estén en la base de datos de destino y que el destino tenga instalada la extensión `pg_columnmask`.

**nota**  
A partir de PostgreSQL 18, `pg_dump` admite la opción `—no-policies` que excluye la seguridad por fila (RLS) y políticas de enmascaramiento de `pg_columnmask` de los volcados de bases de datos. Para obtener más información, consulte [pg\$1dump](https://www.postgresql.org/docs/current/app-pgdump.html).

## Contenedor de datos externos
<a name="AuroraPostgreSQL.Security.DynamicMasking.DataMovement.FDQ"></a>

Cuando se utilizan contenedores de datos externos, las políticas de enmascaramiento en las tablas remotas se aplican en función de los permisos del usuario asignado en el servidor de origen, no de los permisos del usuario local que consulta, y aunque puede acceder a los datos remotos enmascarados mediante FDW, no puede crear políticas de DDM o RLS directamente en las tablas externas de la base de datos local.