Introdução
Em um artigo anterior, apresentamos o básico para entender os esquemas do PostgreSQL, a mecânica de criação e exclusão e analisamos vários casos de uso. Este artigo estenderá esses conceitos básicos e explorará os privilégios de gerenciamento relacionados a esquemas.
Mais sobrecarga de terminologia
Mas há uma questão preliminar que requer esclarecimento. Vale lembrar que no artigo anterior nos detivemos em um possível ponto de confusão relacionado à sobrecarga do termo “esquema”. O significado especializado desse termo no contexto de bancos de dados PostgreSQL é distinto de como é geralmente usado em sistemas de gerenciamento de banco de dados relacional. Temos outra confusão terminológica semelhante possível para o presente tópico relacionada à palavra “público”.
Após a criação inicial do banco de dados, o banco de dados Postgresql recém-criado inclui um esquema predefinido chamado “público”. É um esquema como qualquer outro, mas a mesma palavra também é usada como uma palavra-chave que denota “todos os usuários” em contextos em que, de outra forma, um nome de função real pode ser usado, como ... espere por isso ... gerenciamento de privilégios de esquema . O significado e dois usos distintos serão esclarecidos nos exemplos abaixo.
Privilégios de esquema de consulta
Antes de tornar isso concreto com um código de exemplo para conceder e revogar privilégios de esquema, precisamos revisar como examinar os privilégios de esquema. Usando a interface de linha de comando psql, listamos os esquemas e privilégios associados com o comando \dn+. Para um banco de dados sampledb recém-criado, vemos esta entrada para o esquema público:
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
--------+----------+----------------------+------------------------
public | postgres | postgres=UC/postgres+| standard public schema
| | =UC/postgres |
(1 row)
As duas primeiras e a quarta colunas são bem diretas:como mencionado anteriormente, mostrando o esquema criado por padrão chamado “público”, descrito como “esquema público padrão” e de propriedade da função “postgres”. (A propriedade do esquema, a menos que especificado de outra forma, é definida para a função que cria o esquema.) Essa terceira coluna listando os privilégios de acesso é de interesse aqui. O formato das informações de privilégio fornece três itens:o privilégio concedido, os privilégios e o concedente de privilégio no formato “grantee=privileges/conceder”, ou seja, à esquerda do sinal de igualdade está o papel que recebe o(s) privilégio(s), imediatamente à direita do sinal de igualdade está um grupo de letras especificando o(s) privilégio(s) em particular e, por último, após a barra, o papel que concedeu ao(s) privilégio(s). Pode haver várias especificações de informações de privilégio, listadas separadas por um sinal de mais, pois os privilégios são aditivos.
Para esquemas, existem dois privilégios possíveis que podem ser concedidos separadamente:U para “USAGE” e C para “CREATE”. O primeiro é necessário para que uma função tenha a capacidade de pesquisar objetos de banco de dados, como tabelas e exibições contidas no esquema; o último privilégio permite que uma função crie objetos de banco de dados no esquema. Existem outras letras para outros privilégios relacionados a diferentes tipos de objetos de banco de dados, mas para esquemas, apenas U e C se aplicam.
Assim, para interpretar a lista de privilégios acima, a primeira especificação nos diz que o usuário postgres recebeu a atualização e os privilégios de criação por si mesmo no esquema público.
Observe que para a segunda especificação acima, uma string vazia aparece à esquerda do sinal de igual. É assim que se denotam os privilégios concedidos a todos os usuários, por meio da palavra-chave PUBLIC mencionada anteriormente.
Esta última especificação de conceder uso e criar privilégios no esquema público para todos os usuários é vista por alguns como possivelmente contrária às melhores práticas dos princípios gerais de segurança, onde pode-se preferir começar com acesso restrito por padrão, exigindo que o administrador do banco de dados conceda explicitamente e privilégios de acesso minimamente necessários. Esses privilégios liberais no esquema público são configurados propositalmente no sistema como uma conveniência e para compatibilidade de legado.
Observe também que, exceto pelas configurações de privilégio permissivo, a única outra coisa especial sobre o esquema público é que ele também está listado no search_path, conforme discutimos no artigo anterior. Isso é semelhante por conveniência:a configuração search_path e os privilégios liberais juntos resultam em um novo banco de dados que pode ser usado como se não houvesse o conceito de esquemas.
Antecedentes históricos do esquema público
Essa preocupação de compatibilidade se originou cerca de quinze anos atrás (antes do PostgreSQLversão 7.3, cf. notas de lançamento da versão 7.3) quando o recurso de esquema não fazia parte do PostgreSQL. A configuração do esquema público com privilégios liberais e a presença search_path quando os esquemas foram introduzidos na versão 7.3 permitiram a compatibilidade de aplicativos mais antigos, que não reconhecem esquemas, para funcionar sem modificações com o recurso de banco de dados atualizado.
Caso contrário, não há mais nada particularmente especial sobre o esquema público:alguns DBAs o excluem se seu caso de uso não apresentar nenhum requisito para ele; outros o bloqueiam revogando os privilégios padrão.
Mostre-me o código - Revogando privilégios
Vamos fazer algum código para ilustrar e expandir o que discutimos até agora.
Os privilégios de esquema são gerenciados com os comandos GRANT e REVOKE para adicionar e retirar privilégios, respectivamente. Tentaremos alguns exemplos específicos para bloquear o esquema público, mas a sintaxe geral é:
REVOKE [ GRANT OPTION FOR ]
{ { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA schema_name [, ...]
FROM { [ GROUP ] role_name | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
Então, como um exemplo de bloqueio inicial, vamos remover o privilégio de criação do esquema público. Observe que nesses exemplos a palavra minúscula “público” se refere ao esquema e pode ser substituída por qualquer outro nome de esquema válido que possa existir no banco de dados. A maiúscula “PUBLIC” é a palavra-chave especial que implica “todos os usuários” e pode ser substituída por um nome de função específico ou uma lista de nomes de função separada por vírgulas para um controle de acesso mais refinado.
sampledb=# REVOKE CREATE ON SCHEMA public FROM PUBLIC;
REVOKE
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
--------+----------+----------------------+------------------------
public | postgres | postgres=UC/postgres+| standard public schema
| | =U/postgres |
(1 row)
A única diferença nesta listagem de privilégios de esquema da primeira é a ausência do “C” na segunda especificação de privilégio, verificando se nosso comando foi efetivo:usuários diferentes do usuário postgres não podem mais criar tabelas, visualizações ou outros objetos em o esquema público.
Observe que o comando acima que revoga os privilégios de criação do esquema público é a mitigação recomendada para uma vulnerabilidade publicada recentemente, CVE-2018-1058, que surge da configuração de privilégio padrão no esquema público.
Um nível adicional de bloqueio pode implicar em negar totalmente o acesso de pesquisa ao esquema, removendo o privilégio de uso:
sampledb=# REVOKE USAGE ON SCHEMA public FROM PUBLIC;
REVOKE
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
--------+----------+----------------------+------------------------
public | postgres | postgres=UC/postgres | standard public schema
(1 row)
Como todos os privilégios de esquema disponíveis para usuários não proprietários foram revogados, toda a especificação do segundo privilégio desaparece na listagem acima.
O que fizemos com dois comandos separados poderia ter sido realizado de forma sucinta com um único comando especificando todos os privilégios como:
sampledb=# REVOKE ALL PRIVILEGES ON SCHEMA public FROM PUBLIC;
REVOKE
Além disso, também é possível revogar privilégios do proprietário do esquema:
sampledb=# REVOKE ALL PRIVILEGES ON SCHEMA public FROM postgres;
REVOKE
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
--------+----------+-------------------+------------------------
public | postgres | | standard public schema
(1 row)
mas isso realmente não realiza nada prático, pois o proprietário do esquema retém privilégios totais aos esquemas próprios, independentemente da atribuição explícita simplesmente em virtude da propriedade.
A atribuição de privilégios liberais para o esquema público é um artefato especial associado à criação inicial do banco de dados. Os esquemas criados posteriormente em um banco de dados existente estão em conformidade com a prática recomendada de iniciar sem privilégios atribuídos. Por exemplo, examinar os privilégios do esquema depois de criar um novo esquema chamado “privado” mostra que o novo esquema não tem privilégios:
sampledb=# create schema private;
CREATE SCHEMA
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
---------+----------+----------------------+------------------------
private | postgres | |
public | postgres | | standard public schema
(2 rows)
Baixe o whitepaper hoje PostgreSQL Management &Automation with ClusterControlSaiba o que você precisa saber para implantar, monitorar, gerenciar e dimensionar o PostgreSQLBaixe o whitepaper Mostre-me o Código - Concedendo Privilégios
A forma geral do comando para adicionar privilégios é:
GRANT { { CREATE | USAGE } [, ...] | ALL [ PRIVILEGES ] }
ON SCHEMA schema_name [, ...]
TO role_specification [, ...] [ WITH GRANT OPTION ]
where role_specification can be:
[ GROUP ] role_name
| PUBLIC
| CURRENT_USER
| SESSION_USER
Usando este comando, podemos, por exemplo, permitir que todas as funções pesquisem objetos de banco de dados no esquema privado adicionando o privilégio de uso com
sampledb=# GRANT USAGE ON SCHEMA private TO PUBLIC;
GRANT
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
---------+----------+----------------------+------------------------
private | postgres | postgres=UC/postgres+|
| | =U/postgres |
public | postgres | | standard public schema
(2 rows)
Observe como os privilégios UC aparecem para o proprietário do postgres como a primeira especificação, agora que atribuímos privilégios diferentes do padrão ao esquema. A segunda especificação, =U/postgres, corresponde ao comando GRANT que acabamos de invocar como usuário postgres concedendo privilégio de uso a todos os usuários (onde, lembre-se, a string vazia à esquerda do sinal de igual implica “todos os usuários”).
Uma função específica, chamada “user1”, por exemplo, pode receber privilégios de criação e de uso para o esquema privado com:
sampledb=# GRANT ALL PRIVILEGES ON SCHEMA private TO user1;
GRANT
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
---------+----------+----------------------+------------------------
private | postgres | postgres=UC/postgres+|
| | =U/postgres +|
| | user1=UC/postgres |
public | postgres | | standard public schema
(2 rows)
Ainda não mencionamos a cláusula “WITH GRANT OPTION” do formulário de comando geral. Assim como parece, esta cláusula permite um papel concedido o poder para si mesmo conceder o privilégio especificado a outros usuários, e é indicado na lista de privilégios por asteriscos anexados ao privilégio específico:
sampledb=# GRANT ALL PRIVILEGES ON SCHEMA private TO user1 WITH GRANT OPTION;
GRANT
sampledb=# \dn+
List of schemas
Name | Owner | Access privileges | Description
---------+----------+----------------------+------------------------
private | postgres | postgres=UC/postgres+|
| | =U/postgres +|
| | user1=U*C*/postgres |
public | postgres | | standard public schema
(2 rows)
Conclusão
Isso encerra o assunto de hoje. Como nota final, porém, lembre-se de que discutimos apenas os privilégios de acesso ao esquema. Embora o privilégio USAGE permita a pesquisa de objetos de banco de dados em um esquema, para realmente acessar os objetos para operações específicas, como leitura, gravação, execução etc., a função também deve ter privilégios apropriados para essas operações nesses objetos de banco de dados específicos.