

# Uso de la compatibilidad de extensiones delegadas de Amazon RDS para PostgreSQL
<a name="RDS_delegated_ext"></a>

Al utilizar la compatibilidad de extensiones delegadas de Amazon RDS para PostgreSQL, puede delegar la administración de la extensión a un usuario que no necesita ser un `rds_superuser`. Con esta compatibilidad de extensiones delegadas, se crea un nuevo rol denominado `rds_extension` que debe asignarse a un usuario para que administre otras extensiones. Este rol puede crear, actualizar y eliminar extensiones.

Puede especificar qué extensiones se pueden instalar en la instancia de base de datos de RDS enumerándolas en el parámetro `rds.allowed_extensions`. Para obtener más información, consulte [Uso de extensiones PostgreSQL con Amazon RDS para PostgreSQL](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Extensions.html).

Puede restringir la lista de extensiones disponibles que el usuario puede administrar con el rol `rds_extension` utilizando el parámetro `rds.allowed_delegated_extensions`.

La compatibilidad de extensiones delegadas está disponible en las siguientes versiones:
+ Todas las versiones superiores
+ Versión 16.4 y otras versiones 16 superiores
+ Versión 15.8 y otras versiones 15 superiores
+ Versión 14.13 y otras versiones 14 superiores
+ Versión 13.16 y otras versiones 13 superiores
+ Versión 12.20 y otras versiones 12 superiores

**Topics**
+ [Activación de la compatibilidad con extensiones delegadas a un usuario](#RDSPostgreSQL.delegated_ext_mgmt)
+ [Configuración utilizada en la compatibilidad de extensiones delegadas de RDS para PostgreSQL](#RDSPostgreSQL.delegated_ext_config)
+ [Desactivar la compatibilidad para la extensión delegada](#RDSPostgreSQL.delegated_ext_disable)
+ [Ventajas del uso de la compatibilidad de extensiones delegadas de Amazon RDS](#RDSPostgreSQL.delegated_ext_benefits)
+ [Limitación de la compatibilidad de extensiones delegadas de Amazon RDS para PostgreSQL](#RDSPostgreSQL.delegated_ext_limit)
+ [Permisos necesarios para determinadas extensiones](#RDSPostgreSQL.delegated_ext_perm)
+ [Consideraciones de seguridad](#RDSPostgreSQL.delegated_ext_sec)
+ [Eliminación de extensión en cascada deshabilitada](#RDSPostgreSQL.delegated_ext_drop)
+ [Ejemplos de extensiones que se pueden agregar mediante la compatibilidad de extensiones delegadas](#RDSPostgreSQL.delegated_ext_support)

## Activación de la compatibilidad con extensiones delegadas a un usuario
<a name="RDSPostgreSQL.delegated_ext_mgmt"></a>

Debe realizar lo siguiente para habilitar la compatibilidad con extensiones delegadas en un usuario:

1. **Otorgar el rol `rds_extension` a un usuario**: conéctese a la base de datos como `rds_superuser` y ejecute el siguiente comando:

   ```
   Postgres => grant rds_extension to user_name;
   ```

1. **Defina la lista de extensiones disponibles para que las administren los usuarios delegados**: `rds.allowed_delegated_extensions` permite especificar un subconjunto de las extensiones disponibles utilizando `rds.allowed_extensions` en el parámetro del clúster de base de datos. Puede realizar esto en uno de los siguientes niveles:
   + En el clúster o en el grupo de parámetros de la instancia, a través de la Consola de administración de AWS o la API. Para obtener más información, consulte [Grupos de parámetros para Amazon RDS](USER_WorkingWithParamGroups.md).
   + Use el siguiente comando en el nivel de la base de datos:

     ```
     alter database database_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
   + Use el siguiente comando en el nivel de usuario:

     ```
     alter user user_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
**nota**  
No es necesario reiniciar la base de datos después de cambiar el parámetro dinámico `rds.allowed_delegated_extensions`.

1. **Permita el acceso del usuario delegado a los objetos creados durante el proceso de creación de la extensión**: algunas extensiones crean objetos que requieren la concesión de permisos adicionales antes de que el usuario con el rol `rds_extension` pueda acceder a ellos. El `rds_superuser` debe conceder al usuario delegado acceso a esos objetos. Una de las opciones es utilizar un desencadenador de eventos para conceder automáticamente el permiso al usuario delegado.

   **Ejemplo de desencadenador de eventos**

   Si desea permitir que un usuario delegado con `rds_extension` utilice extensiones que requieran configurar permisos en los objetos creados al crear la extensión, puede personalizar el siguiente ejemplo de un desencadenador de eventos y agregar solo las extensiones para las que desee que los usuarios delegados tengan acceso a todas las funciones. Este activador de eventos se puede crear en la plantilla 1 (la plantilla predeterminada), por lo que todas las bases de datos creadas a partir de la plantilla 1 tendrán ese desencadenador de eventos. Cuando un usuario delegado instala la extensión, este desencadenador otorgará automáticamente la propiedad de los objetos creados por la extensión.

   ```
   CREATE OR REPLACE FUNCTION create_ext()
   
     RETURNS event_trigger AS $$
   
   DECLARE
   
     schemaname TEXT;
     databaseowner TEXT;
   
     r RECORD;
   
   BEGIN
   
     IF tg_tag = 'CREATE EXTENSION' and current_user != 'rds_superuser' THEN
       RAISE NOTICE 'SECURITY INVOKER';
       RAISE NOTICE 'user: %', current_user;
       FOR r IN SELECT * FROM pg_catalog.pg_event_trigger_ddl_commands()
       LOOP
           CONTINUE WHEN r.command_tag != 'CREATE EXTENSION' OR r.object_type != 'extension';
   
           schemaname = (
               SELECT n.nspname
               FROM pg_catalog.pg_extension AS e
               INNER JOIN pg_catalog.pg_namespace AS n
               ON e.extnamespace = n.oid
               WHERE e.oid = r.objid
           );
   
           databaseowner = (
               SELECT pg_catalog.pg_get_userbyid(d.datdba)
               FROM pg_catalog.pg_database d
               WHERE d.datname = current_database()
           );
           RAISE NOTICE 'Record for event trigger %, objid: %,tag: %, current_user: %, schema: %, database_owenr: %', r.object_identity, r.objid, tg_tag, current_user, schemaname, databaseowner;
           IF r.object_identity = 'address_standardizer_data_us' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_gaz TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_lex TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.us_rules TO %I WITH GRANT OPTION;', schemaname, databaseowner);
           ELSIF r.object_identity = 'dict_int' THEN
               EXECUTE pg_catalog.format('ALTER TEXT SEARCH DICTIONARY %I.intdict OWNER TO %I;', schemaname, databaseowner);
           ELSIF r.object_identity = 'pg_partman' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.part_config_sub TO %I WITH GRANT OPTION;', schemaname, databaseowner);
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE %I.custom_time_partitions TO %I WITH GRANT OPTION;', schemaname, databaseowner);
           ELSIF r.object_identity = 'postgis_topology' THEN
               EXECUTE pg_catalog.format('GRANT SELECT, UPDATE, INSERT, DELETE ON ALL TABLES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
               EXECUTE pg_catalog.format('GRANT USAGE ON SCHEMA topology TO %I WITH GRANT OPTION;', databaseowner);
           END IF;
       END LOOP;
     END IF;
   END;
   $$ LANGUAGE plpgsql SECURITY DEFINER;
   
   CREATE EVENT TRIGGER log_create_ext ON ddl_command_end EXECUTE PROCEDURE create_ext();
   ```

## Configuración utilizada en la compatibilidad de extensiones delegadas de RDS para PostgreSQL
<a name="RDSPostgreSQL.delegated_ext_config"></a>


| Nombre de la configuración | Descripción | Valor predeterminado | Notas | Quién puede modificar o conceder el permiso | 
| --- | --- | --- | --- | --- | 
| `rds.allowed_delegated_extensions` | Este parámetro limita las extensiones que un rol de rds\$1extension puede administrar en una base de datos. Debe ser un subconjunto de rds.allowed\$1extensions. | empty string | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/es_es/AmazonRDS/latest/UserGuide/RDS_delegated_ext.html) Para obtener más información sobre la configuración de este parámetro, consulte [Activación de la compatibilidad con extensiones delegadas a un usuario](#RDSPostgreSQL.delegated_ext_mgmt). | rds\$1superuser | 
| `rds.allowed_extensions` | Este parámetro permite que un cliente limite las extensiones que se pueden instalar en la instancia de base de datos de RDS. Para obtener más información, consulte [Restringir la instalación de extensiones de PostgreSQL](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction). | "\$1" | De forma predeterminada, este parámetro está establecido en “\$1”, lo que significa que los usuarios con los privilegios necesarios pueden crear todas las extensiones compatibles con RDS para PostgreSQL y Aurora PostgreSQL. Vacío significa que no se pueden instalar extensiones en la instancia de base de datos de RDS. | administrator | 
| `rds-delegated_extension_allow_drop_cascade` | Este parámetro controla la capacidad del usuario con `rds_extension` de eliminar la extensión mediante una opción en cascada. | apagar | De forma predeterminada, `rds-delegated_extension_allow_drop_cascade` está establecido en `off`. Esto significa que los usuarios con `rds_extension` no pueden eliminar una extensión mediante la opción en cascada. Para otorgar esa habilidad, el parámetro `rds.delegated_extension_allow_drop_cascade` debe configurarse como `on`. | rds\$1superuser | 

## Desactivar la compatibilidad para la extensión delegada
<a name="RDSPostgreSQL.delegated_ext_disable"></a>

**Desactivación parcial**  
Los usuarios delegados no pueden crear nuevas extensiones, pero sí pueden actualizar las existentes.
+ Restablece `rds.allowed_delegated_extensions` al valor predeterminado en el grupo de parámetros del clúster de base de datos.
+ Use el siguiente comando en el nivel de la base de datos:

  ```
  alter database database_name reset rds.allowed_delegated_extensions;
  ```
+ Use el siguiente comando en el nivel de usuario:

  ```
  alter user user_name reset rds.allowed_delegated_extensions;
  ```

**Desactivación completa**  
Al revocar el rol `rds_extension` de un usuario, el usuario recuperará los permisos estándar. El usuario ya no puede crear, actualizar ni eliminar extensiones. 

```
postgres => revoke rds_extension from user_name;
```

## Ventajas del uso de la compatibilidad de extensiones delegadas de Amazon RDS
<a name="RDSPostgreSQL.delegated_ext_benefits"></a>

Al utilizar la compatibilidad de extensiones delegadas de Amazon RDS para PostgreSQL, delega de forma segura la administración de la extensión a los usuarios que no tengan el rol `rds_superuser`. Esta característica proporciona los siguientes beneficios:
+ Puede delegar fácilmente la administración de extensiones a los usuarios de su elección.
+ Esto no requiere el rol `rds_superuser`.
+ Ofrece la posibilidad de admitir diferentes conjuntos de extensiones para diferentes bases de datos en el mismo clúster de base de datos.

## Limitación de la compatibilidad de extensiones delegadas de Amazon RDS para PostgreSQL
<a name="RDSPostgreSQL.delegated_ext_limit"></a>
+ Los objetos creados durante el proceso de creación de la extensión pueden requerir privilegios adicionales para que la extensión funcione correctamente.
+ De forma predeterminada, hay algunas extensiones que el usuario de la extensión delegada no puede administrar, como `log_fdw`, `pg_cron`, `pg_tle`, `pgactive`, `pglogical`, `postgis_raster`, `postgis_tiger_geocoder`, `postgis_topology`.

## Permisos necesarios para determinadas extensiones
<a name="RDSPostgreSQL.delegated_ext_perm"></a>

Para crear, usar o actualizar las siguientes extensiones, el usuario delegado debe tener los privilegios necesarios en las siguientes funciones, tablas y esquemas.


| Extensiones que necesitan propiedad o permisos | Función | Tablas | Esquema | Diccionario de búsqueda de texto | Comment | 
| --- | --- | --- | --- | --- | --- | 
| address\$1standardizer\$1data\$1us | none | us\$1gaz, us\$1lex, us\$1lex, I.us\$1rules | none | none | none | 
| amcheck | bt\$1index\$1check, bt\$1index\$1parent\$1check | none | none | none | none | 
| dict\$1int | none | none | none | intdict | none | 
| pg\$1partman | none | custom\$1time\$1partitions, part\$1config, part\$1config\$1sub | none | none | none | 
| pg\$1stat\$1statements | none | none | none | none | none | 
| PostGIS | st\$1tileenvelope | spatial\$1ref\$1sys | none | none | none | 
| postgis\$1raster | none | none | none | none | none | 
| postgis\$1topology | none | topology, layer | topology | none | el usuario delegado debe ser el propietario de la base de datos | 
| log\$1fdw | create\$1foreign\$1table\$1for\$1log\$1file | none | none | none | none | 
| rds\$1tools | role\$1password\$1encryption\$1type | none | none | none | none | 
| postgis\$1tiger\$1geocoder | none | geocode\$1settings\$1default, geocode\$1settings | tiger | none | none | 
| pg\$1freespacemap | pg\$1freespace | none | none | none | none | 
| pg\$1visibility | pg\$1visibility | none | none | none | none | 

## Consideraciones de seguridad
<a name="RDSPostgreSQL.delegated_ext_sec"></a>

 Tenga en cuenta que un usuario con el rol `rds_extension` podrá administrar las extensiones en todas las bases de datos en las que tenga el privilegio de conexión. Si la intención es que un usuario delegado administre la extensión en una única base de datos, una práctica recomendada consiste en revocar todos los privilegios del público en cada base de datos y, a continuación, conceder de forma explícita el privilegio de conexión para esa base de datos específica al usuario delegado. 

 Existen varias extensiones que permiten a un usuario acceder a la información de varias bases de datos. Asegúrese de que los usuarios a los que conceda `rds_extension` tengan capacidades para múltiples bases de datos antes de agregar estas extensiones a `rds.allowed_delegated_extensions`. Por ejemplo, `postgres_fdw` y `dblink` proporcionan la funcionalidad de realizar consultas en todas las bases de datos de la misma instancia o de instancias remotas. `log_fdw` lee los archivos de registro del motor postgres, que son de todas las bases de datos de la instancia, y pueden contener consultas lentas o mensajes de error de varias bases de datos. `pg_cron` permite ejecutar trabajos en segundo plano programados en la instancia de base de datos y puede configurar los trabajos para que se ejecuten en una base de datos diferente. 

## Eliminación de extensión en cascada deshabilitada
<a name="RDSPostgreSQL.delegated_ext_drop"></a>

 La posibilidad de eliminar la extensión con la opción en cascada por parte de un usuario con el rol `rds_extension` la controla el parámetro `rds.delegated_extension_allow_drop_cascade`. De forma predeterminada, `rds-delegated_extension_allow_drop_cascade` está establecido en `off`. Esto significa que los usuarios con el tol `rds_extension` no pueden eliminar una extensión mediante la opción en cascada como se muestra en la siguiente consulta. 

```
DROP EXTENSION CASCADE;
```

Esto eliminará automáticamente los objetos que dependan de la extensión y, a su vez, todos los objetos que dependan de esos objetos. El intento de utilizar la opción en cascada generará un error.

 Para otorgar esa habilidad, el parámetro `rds.delegated_extension_allow_drop_cascade` debe configurarse como `on`. 

 Cambiar el parámetro dinámico `rds.delegated_extension_allow_drop_cascade` no requiere un reinicio de la base de datos. Puede realizar esto en uno de los siguientes niveles: 
+ En el clúster o en el grupo de parámetros de la instancia, a través de la Consola de administración de AWS o la API.
+ Con el siguiente comando en el nivel de la base de datos:

  ```
  alter database database_name set rds.delegated_extension_allow_drop_cascade = 'on';
  ```
+ Con el siguiente comando en el nivel de usuario:

  ```
  alter role tenant_user set rds.delegated_extension_allow_drop_cascade = 'on';
  ```

## Ejemplos de extensiones que se pueden agregar mediante la compatibilidad de extensiones delegadas
<a name="RDSPostgreSQL.delegated_ext_support"></a>
+ `rds_tools`

  ```
  extension_test_db=> create extension rds_tools;
  CREATE EXTENSION
  extension_test_db=> SELECT * from rds_tools.role_password_encryption_type() where rolname = 'pg_read_server_files';
  ERROR: permission denied for function role_password_encryption_type
  ```
+ `amcheck`

  ```
  extension_test_db=> CREATE TABLE amcheck_test (id int);
  CREATE TABLE
  extension_test_db=> INSERT INTO amcheck_test VALUES (generate_series(1,100000));
  INSERT 0 100000
  extension_test_db=> CREATE INDEX amcheck_test_btree_idx ON amcheck_test USING btree (id);
  CREATE INDEX
  extension_test_db=> create extension amcheck;
  CREATE EXTENSION
  extension_test_db=> SELECT bt_index_check('amcheck_test_btree_idx'::regclass);
  ERROR: permission denied for function bt_index_check
  extension_test_db=> SELECT bt_index_parent_check('amcheck_test_btree_idx'::regclass);
  ERROR: permission denied for function bt_index_parent_check
  ```
+ `pg_freespacemap`

  ```
  extension_test_db=> create extension pg_freespacemap;
  CREATE EXTENSION
  extension_test_db=> SELECT * FROM pg_freespace('pg_authid');
  ERROR: permission denied for function pg_freespace
  extension_test_db=> SELECT * FROM pg_freespace('pg_authid',0);
  ERROR: permission denied for function pg_freespace
  ```
+ `pg_visibility`

  ```
  extension_test_db=> create extension pg_visibility;
  CREATE EXTENSION
  extension_test_db=> select * from pg_visibility('pg_database'::regclass);
  ERROR: permission denied for function pg_visibility
  ```
+ `postgres_fdw`

  ```
  extension_test_db=> create extension postgres_fdw;
  CREATE EXTENSION
  extension_test_db=> create server myserver foreign data wrapper postgres_fdw options (host 'foo', dbname 'foodb', port '5432');
  ERROR: permission denied for foreign-data wrapper postgres_fdw
  ```