

# Usar a compatibilidade com extensões delegadas do Amazon RDS para PostgreSQL
<a name="RDS_delegated_ext"></a>

Usando a compatibilidade com extensões delegadas do PostgreSQL, é possível delegar o gerenciamento de extensões a um usuário que não precise ser um `rds_superuser`. Com esse suporte de extensão delegado, um novo perfil chamado `rds_extension` é criado, e você deve atribuí-lo a um usuário para gerenciar outras extensões. Esse perfil pode criar, atualizar e eliminar extensões.

É possível especificar quais extensões podem ser instaladas na instância de banco de dados do RDS listando-as no parâmetro `rds.allowed_extensions`. Para obter mais informações, consulte [Usar extensões PostgreSQL com o Amazon RDS para PostgreSQL](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Extensions.html).

É possível restringir a lista de extensões disponíveis que podem ser gerenciadas pelo usuário com o perfil `rds_extension` usando o parâmetro `rds.allowed_delegated_extensions`.

O suporte de extensão delegado está disponível nas seguintes versões:
+ Todas as versões posteriores
+ 16.4 e versões 16 posteriores
+ 15.8 e versões 15 posteriores
+ 14.13 e versões 14 posteriores
+ 13.16 e versões 13 posteriores
+ 12.20 e versões 12 posteriores

**Topics**
+ [Ativar o suporte de extensão delegado a um usuário](#RDSPostgreSQL.delegated_ext_mgmt)
+ [Configuração usada na compatibilidade com extensões delegadas do PostgreSQL](#RDSPostgreSQL.delegated_ext_config)
+ [Desativar o suporte para a extensão delegada](#RDSPostgreSQL.delegated_ext_disable)
+ [Benefícios de usar a compatibilidade com extensões delegadas do Amazon RDS](#RDSPostgreSQL.delegated_ext_benefits)
+ [Limitação da compatibilidade com extensões delegadas do PostgreSQL](#RDSPostgreSQL.delegated_ext_limit)
+ [Permissões necessárias para determinadas extensões](#RDSPostgreSQL.delegated_ext_perm)
+ [Considerações sobre segurança](#RDSPostgreSQL.delegated_ext_sec)
+ [Descartar cascata de extensão desabilitado](#RDSPostgreSQL.delegated_ext_drop)
+ [Exemplos de extensões que podem ser adicionadas usando o suporte de extensão delegado](#RDSPostgreSQL.delegated_ext_support)

## Ativar o suporte de extensão delegado a um usuário
<a name="RDSPostgreSQL.delegated_ext_mgmt"></a>

É necessário executar o seguinte para habilitar o suporte de extensão delegado a um usuário:

1. **Conceder o perfil `rds_extension` a um usuário**: conecte-se ao banco de dados `rds_superuser` e execute o seguinte comando:

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

1. **Definir a lista de extensões disponíveis para usuários delegados gerenciarem**: o `rds.allowed_delegated_extensions` permite que você especifique um subconjunto das extensões disponíveis usando o parâmetro de cluster de banco de dados `rds.allowed_extensions`. É possível fazer isso em um dos seguintes níveis:
   + No cluster ou no grupo de parâmetros da instância, por meio do Console de gerenciamento da AWS ou da API. Para obter mais informações, consulte [Grupos de parâmetros para Amazon RDS](USER_WorkingWithParamGroups.md).
   + Use o seguinte comando em nível de banco de dados:

     ```
     alter database database_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
   + Use o seguinte comando em nível de usuário:

     ```
     alter user user_name set rds.allowed_delegated_extensions = 'extension_name_1,
                         extension_name_2,...extension_name_n';
     ```
**nota**  
Não é necessário reiniciar o banco de dados depois de alterar o parâmetro dinâmico `rds.allowed_delegated_extensions`.

1. **Permitir que o usuário delegado acesse os objetos criados durante o processo de criação da extensão**: determinadas extensões criam objetos que exigem que permissões adicionais sejam concedidas para que o usuário com o perfil `rds_extension` possa acessá-los. O `rds_superuser` deve conceder ao usuário delegado acesso a esses objetos. Uma das opções é usar um gatilho de eventos para conceder permissão automaticamente ao usuário delegado.

   **Exemplo de gatilho de eventos**

   Se quiser permitir que um usuário delegado com `rds_extension` use extensões que exijam permissões de configuração nos objetos criados pela criação da extensão, você poderá personalizar o exemplo abaixo de um gatilho de eventos e adicionar somente as extensões para as quais você deseja que os usuários delegados tenham acesso à funcionalidade completa. Esse gatilho de eventos pode ser criado no modelo 1 (o modelo padrão), portanto, todo banco de dados criado a partir do modelo 1 terá esse gatilho de eventos. Quando um usuário delegado instalar a extensão, esse gatilho concederá automaticamente a propriedade dos objetos criados pela extensão.

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

## Configuração usada na compatibilidade com extensões delegadas do PostgreSQL
<a name="RDSPostgreSQL.delegated_ext_config"></a>


| Nome da configuração | Descrição | Valor padrão | Observações | Quem pode modificar ou conceder permissão | 
| --- | --- | --- | --- | --- | 
| `rds.allowed_delegated_extensions` | Esse parâmetro limita as extensões que um perfil rds\$1extension pode gerenciar em um banco de dados. Ele deve ser um subconjunto de rds.allowed\$1extensions. | string vazia | [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/pt_br/AmazonRDS/latest/UserGuide/RDS_delegated_ext.html) Para saber mais sobre como configurar esse parâmetro, consulte [Ativar o suporte de extensão delegado a um usuário](#RDSPostgreSQL.delegated_ext_mgmt). | rds\$1superuser | 
| `rds.allowed_extensions` | Esse parâmetro permite que o cliente limite as extensões que podem ser instaladas na instância de banco de dados do RDS. Para ter mais informações, consulte [Restringir a instalação de extensões do PostgreSQL](https://docs.aws.amazon.com//AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.FeatureSupport.Extensions.Restriction). | "\$1" | Por padrão, esse parâmetro é definido como “\$1”, o que significa que todas as extensões aceitas no RDS para PostgreSQL e no Aurora PostgreSQL podem ser criadas por usuários com os privilégios necessários. Vazio significa que nenhuma extensão pode ser instalada na instância de banco de dados do RDS. | administrador | 
| `rds-delegated_extension_allow_drop_cascade` | Esse parâmetro controla a capacidade do usuário com `rds_extension` de eliminar a extensão usando uma opção em cascata. | desligar | Por padrão, `rds-delegated_extension_allow_drop_cascade` é definido como `off`. Isso significa que os usuários com `rds_extension` não têm permissão para descartar uma extensão usando a opção em cascata. Para conceder essa capacidade, o parâmetro `rds.delegated_extension_allow_drop_cascade` deve ser definido como `on`. | rds\$1superuser | 

## Desativar o suporte para a extensão delegada
<a name="RDSPostgreSQL.delegated_ext_disable"></a>

**Desativar parcialmente**  
Os usuários delegados não podem criar extensões, mas ainda podem atualizar as existentes.
+ Redefina `rds.allowed_delegated_extensions` como o valor padrão no grupo de parâmetros de cluster de banco de dados.
+ Use o seguinte comando em nível de banco de dados:

  ```
  alter database database_name reset rds.allowed_delegated_extensions;
  ```
+ Use o seguinte comando em nível de usuário:

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

**Desativar totalmente**  
Revogar o perfil `rds_extension` de um usuário vai restaurar as permissões padrão do usuário. O usuário não pode mais criar, atualizar nem descartar extensões. 

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

## Benefícios de usar a compatibilidade com extensões delegadas do Amazon RDS
<a name="RDSPostgreSQL.delegated_ext_benefits"></a>

Usando a compatibilidade com extensões delegadas do PostgreSQL, é possível delegar, com segurança, o gerenciamento de extensões a usuários que não têm o perfil `rds_superuser`. Esse recurso oferece os seguintes benefícios:
+ É possível delegar facilmente o gerenciamento de extensões aos usuários de sua escolha.
+ Isso não exige o perfil `rds_superuser`.
+ Oferece a capacidade de oferecer compatibilidade com um conjunto diferente de extensões para bancos de dados diferentes no mesmo cluster de banco de dados.

## Limitação da compatibilidade com extensões delegadas do PostgreSQL
<a name="RDSPostgreSQL.delegated_ext_limit"></a>
+ Objetos criados durante o processo de criação da extensão podem exigir privilégios adicionais para que a extensão funcione corretamente.
+ Algumas extensões não podem ser gerenciadas pelo usuário da extensão delegada por padrão, incluindo as seguintes: `log_fdw`, `pg_cron`, `pg_tle`, `pgactive`, `pglogical`, `postgis_raster`, `postgis_tiger_geocoder`, `postgis_topology`.

## Permissões necessárias para determinadas extensões
<a name="RDSPostgreSQL.delegated_ext_perm"></a>

Para criar, usar ou atualizar as extensões a seguir, o usuário delegado deve ter os privilégios necessários nestas funções, tabelas e esquemas.


| Extensões que precisam de propriedade ou permissões | Função | Tabelas | Schema | Dicionário de pesquisa de texto | Comment | 
| --- | --- | --- | --- | --- | --- | 
|  address\$1standardizer\$1data\$1us | nenhuma | us\$1gaz, us\$1lex, us\$1lex, I.us\$1rules | nenhuma | nenhuma | nenhuma | 
| amcheck | bt\$1index\$1check, bt\$1index\$1parent\$1check | nenhuma | nenhuma | nenhuma | nenhuma | 
| dict\$1int | nenhuma | nenhuma | nenhuma | intdict | nenhuma | 
| pg\$1partman | nenhuma | custom\$1time\$1partitions, part\$1config, part\$1config\$1sub | nenhuma | nenhuma | nenhuma | 
| pg\$1stat\$1statements | nenhuma | nenhuma | nenhuma | nenhuma | nenhuma | 
| PostGIS | st\$1tileenvelope | spatial\$1ref\$1sys | nenhuma | nenhuma | nenhuma | 
| postgis\$1raster | nenhuma | nenhuma | nenhuma | nenhuma | nenhuma | 
|  postgis\$1topology | nenhuma | topologia, camada | topologia | nenhuma | o usuário delegado deve ser o proprietário do banco de dados | 
| log\$1fdw | create\$1foreign\$1table\$1for\$1log\$1file | nenhuma | nenhuma | nenhuma | nenhuma | 
| rds\$1tools | role\$1password\$1encryption\$1type | nenhuma | nenhuma | nenhuma | nenhuma | 
|  postgis\$1tiger\$1geocoder | nenhuma | geocode\$1settings\$1default, geocode\$1settings | tiger | nenhuma | nenhuma | 
| pg\$1freespacemap | pg\$1freespace | nenhuma | nenhuma | nenhuma | nenhuma | 
| pg\$1visibility | pg\$1visibility | nenhuma | nenhuma | nenhuma | nenhuma | 

## Considerações sobre segurança
<a name="RDSPostgreSQL.delegated_ext_sec"></a>

 Lembre-se de que um usuário com o perfil `rds_extension` poderá gerenciar extensões em todos os bancos de dados nos quais tiver o privilégio de conexão. Se a intenção for fazer com que um usuário delegado gerencie a extensão em um único banco de dados, uma prática recomendada é revogar todos os privilégios públicos em cada banco de dados e, depois, conceder explicitamente o privilégio de conexão desse banco de dados específico ao usuário delegado. 

 Existem várias extensões que podem permitir que um usuário acesse informações de vários bancos de dados. Garanta que os usuários que receberem `rds_extension` tenham recursos de vários bancos de dados antes de adicionar essas extensões a `rds.allowed_delegated_extensions`. Por exemplo, `postgres_fdw` e `dblink` oferecem a capacidade de consultar vários bancos de dados na mesma instância ou em instâncias remotas. `log_fdw` lê os arquivos de log do mecanismo postgres, relacionados a todos os bancos de dados na instância, possivelmente contendo consultas lentas ou mensagens de erro de vários bancos de dados. `pg_cron` permite a execução de trabalhos agendados em segundo plano na instância de banco de dados e pode configurar trabalhos para execução em um banco de dados diferente. 

## Descartar cascata de extensão desabilitado
<a name="RDSPostgreSQL.delegated_ext_drop"></a>

 A capacidade de descartar a extensão com a opção em cascata por um usuário com o perfil `rds_extension` é controlada pelo parâmetro `rds.delegated_extension_allow_drop_cascade`. Por padrão, `rds-delegated_extension_allow_drop_cascade` é definido como `off`. Isso significa que os usuários com o perfil `rds_extension` não têm permissão para descartar uma extensão usando a opção em cascata, conforme mostrado na consulta a seguir. 

```
DROP EXTENSION CASCADE;
```

Pois isso descartará automaticamente os objetos que dependem da extensão e, por sua vez, todos os objetos que dependem desses objetos. A tentativa de usar a opção em cascata gerará um erro.

 Para conceder essa capacidade, o parâmetro `rds.delegated_extension_allow_drop_cascade` deve ser definido como `on`. 

 Alterar o parâmetro dinâmico `rds.delegated_extension_allow_drop_cascade` não requer a reinicialização do banco de dados. É possível fazer isso em um dos seguintes níveis: 
+ No cluster ou no grupo de parâmetros da instância, por meio do Console de gerenciamento da AWS ou da API.
+ Usar o seguinte comando em nível de banco de dados:

  ```
  alter database database_name set rds.delegated_extension_allow_drop_cascade = 'on';
  ```
+ Usar o seguinte comando em nível de usuário:

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

## Exemplos de extensões que podem ser adicionadas usando o suporte de extensão delegado
<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
  ```