Eu quero criar um logon que não tenha a capacidade de gravar em qualquer banco de dados - não apenas bancos de dados que existem hoje, mas qualquer banco de dados recém-criado ou banco de dados restaurado de outros servidores.
Não posso usar funções somente de banco de dados (nem mesmo no modelo), porque elas não terão efeito em bancos de dados recém-restaurados.
(Propósito comercial: estou escrevendo uma postagem no blog sobre como as pessoas podem configurar um novo login para si mesmas com baixo privilégio e podem garantir que não tenham acidentalmente um momento "oops" ao copiar/colar código ou execute-o sem uma cláusula where.)
Se você pudesse viver com um tempo finito (mínimo de 10 segundos) entre as execuções para capturar bancos de dados novos/restaurados, você poderia criar um trabalho agendado do SQL Server Agent e colocar algo assim em uma etapa de trabalho T-SQL: -
você não pode usar um gatilho de login e uma negação no DIU? Toda vez que o usuário faz login, acho que precisaria iterar os bancos de dados e adicionar os DENYs a qualquer banco de dados recém-adicionado.
Alguém pode tornar isso mais simples, mas aqui está minha abordagem:
Crie a função de servidor para "Administradores somente leitura" e atribua as seguintes permissões para permitir permissões em todo o servidor de recursos específicos, como a capacidade de ver a definição de todos os objetos e exibir o estado do servidor. Isso também cria um "bucket" para quais usuários você deseja atribuir às funções de banco de dados individuais:
Crie um procedimento armazenado em [master] para criar/atualizar um grupo de usuários específico do banco de dados que concede leituras, mas nega gravações no banco de dados especificado. Estou usando um proc armazenado, pois você provavelmente precisará executar dentro do contexto do banco de dados especificado, de modo que o sql dinâmico é a primeira solução que vem à mente. Observe que esta solução força você a usar um nome de grupo específico, você pode alterá-lo para o que quiser.
EDIT: Conforme observado em outra solução, o procedimento armazenado precisa verificar se o banco de dados que está sendo adicionado/atualizado está no modo ONLINE. Se não, deve apenas fazer um loop e verificar a cada 5 segundos ou mais?
Em seguida é adicionar um gatilho ddl para cobrir todos os eventos CREATE_DATABASE e ALTER_DATABASE. Esse gatilho precisa ser ajustado para lidar com cenários de alta disponibilidade, bem como alterações aleatórias na compatibilidade, modelo de recuperação etc. Além disso, o gatilho analisará o nome do banco de dados. Estou roubando de [Bob Pusateri] https://www.bobpusateri.com/archive/2018/09/a-tale-of-a-trigger/ para o manuseio de HA. Também não tenho certeza de como impedir que o gatilho seja acionado em atualizações não invasivas (como compatibilidade, modelo de recuperação, modo de usuário etc.). Acho que uma pessoa mais inteligente terá que lidar com isso. :)
Agora, o acima abrange sempre que você adiciona um novo banco de dados ou atualiza um banco de dados na instância. O que você faz quando está apenas adicionando um novo login ao SERVER ROLE acima? Em cima da minha cabeça está criando outro proc armazenado (ou simplesmente alterando o proc armazenado acima para lidar com TODOS os bancos de dados locais e, em seguida, adicionando todos os usuários no SERVER ROLE a todos os bancos de dados que não são do sistema). Em seguida, junte isso com outro gatilho DDL que apenas analisa o evento ADD_SERVER_ROLE_MEMBER e, em seguida, apenas o SERVER ROLE específico "ReadOnlyAdmins".
Outros furos que identifiquei:
Obrigado.
Eu encontrei isso talvez este possa ajudar com a parte de restauração.
Executar procedimento armazenado automaticamente após qualquer evento RESTORE DATABASE
Acho que usaria um gatilho com escopo de servidor e qualquer comando Criar banco de dados ou Restaurar banco de dados seguiria imediatamente um usuário de criação e negaria o IUD no banco de dados recém-criado ou restaurado:
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-trigger-transact-sql?view=sql-server-ver15
CRIAR TRIGGER ddl_trig_database
EM TODOS OS SERVIDOR
PARA CREATE_DATABASE
AS
VAI
Eu tive um caso de uso dentro de um trabalho que parece semelhante em escopo, no qual me disseram que eu tinha que permitir o acesso de leitura de uma determinada conta em bancos de dados novos e existentes. Eu não queria permitir que o usuário fizesse alterações nos níveis de banco de dados e servidor.
Depois de pesquisar como fazer isso, descobri que, a partir do SQL Server 2016, você pode criar uma função de servidor personalizado à qual pode aplicar duas concessões.
CONECTE QUALQUER BANCO DE DADOS e SELECIONE TODOS OS SEGURÁVEIS DO USUÁRIO
Entre essas duas concessões, você está concedendo acesso somente leitura a todos os bancos de dados que existem atualmente, recém-criados ou que foram restaurados do backup em uma determinada instância. Negar gravações está implícito porque você precisa conceder à função de servidor as permissões para permitir gravações.
Do topo da minha cabeça, talvez criar um login e negar tudo a ele e permitir apenas selecionar/inserir/atualizar/excluir por meio de procs armazenados personalizados?