Controlando permissões administrativas com sudo

Se você usa o seu PC Linux como um laboratório para testes ou administra algum/alguns servidores Linux, é certo que você precise digitar a sua senha administrativa inúmeras vezes ao dia.

Neste segundo caso (administração de servidores), se você ainda divide a tarefa com outras pessoas, há um cuidado extra e necessário para manter registrado quem tem a senha privilegiada, quando ela foi alterada ou mesmo o que cada administrador pode fazer. Com o passar do tempo torna-se bem comum ninguém lembrar mais disso e perde-se o controle de acesso da máquina.

É aqui que entra o “sudo”, uma ferramenta que permite conceder privilégios administrativos para que algumas pessoas possam executar apenas comandos pontuais, sem lhes passar a senha do root. Vamos juntos entender um pouco sobre esta ferramenta.

Embora o tema seja o “sudo”, há algumas opções para permitir a execução de comandos administrativos e que todo aspirante a sysadmin deve conhecer (ao menos o nome).

Existem ferramentas de terceiros tanto comerciais quanto livres e gratuitas, como o “Doas” e “Calife” que podem fazer a mesma tarefa mas eu confesso que ainda não me senti confortável a experimentar nenhuma delas.

O sudo tem me atendido muito bem há anos, e creio que para maioria dos sysadmin ela também atenderá satisfatoriamente, mas caso você tenha curiosidade e queira explorar este universo, o website do “Sudo” possui uma página com alternativas que pode ser o seu ponto de partida.

Opções comuns para execução de um comando administrativo

Antes de nos aprofundarmos no “sudo” vamos ver as alternativas existentes em todas as principais distribuições Linux, para login administrativo.

Imagine que você precise exibir o arquivo de senhas do sistema (/etc/shadow), o que só pode ser feito pelo usuário root.

O comando base para isso é bem simples, mas como se vê no exemplo abaixo, sem as devidas permissões, não é possível concluir o que nos propomos.

welrbraga@desk:~$ cat /etc/shadow
cat: /etc/shadow: Permission denied

O resultado será o mesmo (embora, talvez, com mensagens diferentes) caso tentemos executar qualquer outro comando que requeira privilégios de root ou outro usuário que não o nosso.

Há então três opções disponíveis na maioria das distribuições que nos permite realizar esta tarefa. Vejamos.

1. Entrar no sistema como root

Esta é forma mais elementar. Independente de qual seja o seu login no sistema, você precisará iniciar uma nova sessão de terminal e entrar com o login e senha do usuário root, para então digitar o seu comando.

Como root, ou qualquer usuário que tenha as devidas permissões, o seu comando retornará com sucesso:

root@desk:~# cat /etc/shadow
root:$6$4cKG77YkoDIDGsPr$5OfxNh.iwa5Ha419uV/yG8VKa.WpU2/hsS2zcS9CTxJjfyuP1puNi9iZYn.YdIXgS1:18784:0:99999:7:::
daemon:*:18113:0:99999:7:::
bin:*:18113:0:99999:7:::
sys:*:18113:0:99999:7:::
sync:*:18113:0:99999:7:::
[...]

Um problema nesta abordagem, que devemos mitigar, é o fato que para fazer login com o usuário “root” é necessário termos a sua senha.

2. O comando “su”

Uma alternativa a opção anterior é usar o comando “su” (substitute user). A partir da sessão que você está logado (com o seu usuário), execute o comando “su” para entrar como outro usuário e então já poderá executar os comandos com privilégios que aquele novo usuário possua.

No exemplo abaixo, eu usei o comando “su” que substitui o meu usuário pelo “root” e em seguida, executo o comando “cat” com os devidos privilégios.

welrbraga@desk:~$ su root
Senha: 
root@desk:~#

root@desk:~# cat /etc/shadow
root:$6$4cKG77YkoDIDGsPr$5OfxNh.iwa5Ha419uV/yG8VKa.WpU2/hsS2zcS9CTxJjfyuP1puNi9iZYn.YdIXgS1:18784:0:99999:7:::
daemon:*:18113:0:99999:7:::
bin:*:18113:0:99999:7:::
sys:*:18113:0:99999:7:::
sync:*:18113:0:99999:7:::
[...]

Um jeito curto de executar essa mesma tarefa apenas com uma linha de comando é usar o argumento “-c / –command” do comando “su”, como segue:

welrbraga@desk:~$ su root -c 'cat /etc/shadow'
Senha: 
root:$6$4cKG77YkoDIDGsPr$5OfxNh.iwa5Ha419uV/yG8VKa.WpU2/hsS2zcS9CTxJjfyuP1puNi9iZYn.YdIXgS1:18784:0:99999:7:::
daemon:*:18113:0:99999:7:::
bin:*:18113:0:99999:7:::
sys:*:18113:0:99999:7:::
sync:*:18113:0:99999:7:::
[...]

Entretanto, é importante notar, que tal como ocorre com login de root, o uso do comando “su” também requer o conhecimento da senha do root, o que não é uma boa prática (e justamente o que devemos evitar).

Quando estamos falando do seu desktop, talvez isso seja irrelevante, mas quando a máquina em questão é um dos muitos servidores com arquivos, páginas, bancos de dados etc da sua empresa, a curadoria das contas administrativas passam a ser uma tarefa importante do ponto de vista da segurança.

A situação tende a ficar pior se houver dois ou mais administradores, ou uma grande rotatividade dos funcionários, o que em pouco tempo tornará um caos saber quem tem a senha do root ou qual é a mais recente.

Daqui vem então a nossa terceira alternativa (e a mais recomendada).

3. O comando “sudo”

O comando sudo é um velho conhecido dos usuários de sistemas Linux/Unix, porém pouco compreendido.

Ele permite a qualquer usuário preconfigurado executar comandos com os privilégios de um outro usuário, mas ao contrário do que ocorre com o comando “su” não há necessidade de saber a senha do “root”, ou do outro usuário.

Além disso, é possível usar um complexo esquema de permissões permitindo que o usuário execute somente os comandos que ele realmente precisará usar.

Daqui em diante vamos focar apenas neste comando e em como construir as regras de autorização para que você possa controlar o que seus usuários podem ou não fazer em seu sistema.

Arquivo e pasta de configuração sudoers

As regras que definem as permissões dos usuários costumavam ser descritas no arquivo global /etc/sudoers, mas como este arquivo possui regras padrões (e que variam de acordo com a sua distribuição Linux), é melhor não alterá-lo.

A recomendação atual (normalmente escrita em um comentário sobre isso dentro do arquivo /etc/sudoers – ao menos nos sistemas Ubuntu e Debian) é que ao invés de personalizar este arquivo, nós criemos um arquivo dentro do diretório /etc/sudoers.d com as nossas regras.

Você pode seguir esta dica criando um único arquivo com todas as regras personalizadas, ou se preferir, criar um arquivo para cada grupo de regras, ou um arquivo por usuário, inclusive pode criar um único arquivo para todas as suas máquinas, ou para um grupo de máquinas compartilhando as mesmas regras, usando alguma ferramenta de orquestração ou autodeploy … enfim. Você é quem decide.

Quem pode alterar as regras do sudo?

Inicialmente apenas o usuário “root” pode criar novos usuários e definir suas permissões, incluindo ai editar o conteúdo dos arquivos e diretório sudoers.d.

Ou seja, tudo parte do princípio, que já haja alguém com o poder pleno para para alterar estes arquivos e as permissões dos usuários.

Uma boa prática pósinstalação de um ambiente novo é que a senha do usuário root seja usada para dar as devidas permissões iniciais aos primeiros usuários (incluindo ai, alguém que possa definir novas permissões) e em seguida desativa-se a conta do root, ou guardemos a sua senha em um cofre.

Particularmente não gosto da opção de revogar a senha / desativar o login do usuário root – embora adotada por padrão em algumas distribuições (já passei por situações que tê-la a mão foi uma salvação) ; então minha recomendação é que seja realmente uma senha segura e que guardemos em algum documento de acesso restrito ou um cofre de senhas, com uma boa política de acesso e atualização definida e obedecida.

Estrutura das regras

A estrutura de regras no sudoers segue um padrão simples. Ele parece um pouco confuso no princípio, mas depois de escrever e ver funcionando as suas primeiras regras a sua simplicidade fica evidente.

Para nossos propósitos vamos memorizar que a sintaxe seja esta que segue abaixo:

login  maquina  = (usuario:grupo) comandos

Neste contexto temos:

  • login = O login do usuário que estamos dando permissão para usar o sudo (por exemplo, seu login, ou do novo contratado que administrará seu servidor)
  • maquina = O nome da máquina (hostname), onde esta regra será válida. O mais comum é usar o hostname da máquina ou a palavra -chave ALL, mas em um contexto mais complexo poderiamos usar o nome de diversas máquinas aqui
  • usuário:grupo = O usuário:grupo substituto, que o usuário identificado pelo “login” poderá assumir através do “sudo”. O mais comum seria “root”, mas pode ser outros como “postgres”, “www-data”, “apache2” ou outro que tenha permissão para executar os comandos desejados.
  • comandos = A lista de comandos que o usuário poderá executar através do sudo, com esta regra.

Todos os campos poderão receber um valor específico conforme o caso, um “alias” (que veremos adiante), ou ainda a palavra chave “ALL” que significa “tudo” dentro daquele contexto.

Por exemplo “ALL” no campo comando, significa todos os comandos disponíveis no sistema, enquanto “ALL” no campo “login” significa “todos os usuários” etc.

Exemplos de regras

Para os nossos exemplos a seguir, salvo se especificado ao contrário, as regras estarão todas em um único arquivo que vamos chamar de /etc/sudoers.d/exemplo-sudo, desta forma ficará mais fácil de remover todas elas depois dos testes, mas como já dito antes, coloque o nome que desejar.

Uma vez que o arquivo de regras esteja escrito e salvo, se as regras forem aceitas, elas já estarão automaticamente válidas e ativas, sem necessidade de reiniciar algum serviço ou dar qualquer outra instrução ao seu sistema.

Exemplo 1: Regra básica

A regra a seguir permitirá que o usuário de login “daniel”, na máquina “weldesk” (este é o hostname da minha máquina), consiga se passar pelo usuário “root” e usar os comandos “ls” e “cat” com os privilégios adequados.

daniel  weldesk  = (root) /usr/bin/ls, /usr/bin/cat

Uma regra dessas pode ser útil para permitir que o tal Daniel, por exemplo, possa ler os arquivos da máquina, sem no entanto ter permissão para gravá-los ou modificá-los.

Com isso, para que o Daniel possa ver o conteúdo de um arquivo que sozinho não tenha permissão, bastaria invocar o comando cat com privilégios de root através do sudo. Veja os testes a seguir.

Na primeira tentativa o acesso ao arquivo foi negado porque o usuário Daniel não possui permissão para acessar o arquivo, enquanto que na segunda tentativa, agora usando o sudo, ele recebeu temporariamente as permissões do root (usuário substituto padrão) e conseguiu ver o conteúdo do arquivo solicitado.

daniel@weldesk:~$ cat /etc/shadow
cat: /etc/shadow: Permissão negada

daniel@weldesk:~$ sudo cat /etc/shadow
root:$6$4c187YYkoDIDGBPr$6OfxNh.iwa5HlVa419uV/yG811a.WpU2/hsS2zcSrCTxJjfyuh19uN59iZYn.YdIXgS.68wmX6mpBCk6CqdB71:18784:0:99999:7:::
daemon::18113:0:99999:7::: bin::18113:0:99999:7:::
sys::18113:0:99999:7::: sync::18113:0:99999:7:::
[...]

Onde está o arquivo do comando que eu quero?

Você deve ter observado que ao escrever a regra eu indiquei o caminho completo para o arquivo executável do comandos.

Por exemplo, “/usr/bin/ls” ao invés de apenas “ls”. E ainda “/usr/bin/cat”, ao invés de apenas usar “cat”.

É imprescindível que informemos o caminho completo para o arquivo do comando desejado, do contrário o usuário poderia burlar a segurança do sistema criando um arquivo malicioso com o nome de qualquer comando que ele tenha autorização de executar.

Caso você precise definir um comando no sudo e que não saiba a sua localização, use o comando “which” para determinar esta informação.

Exemplo: Onde estão os executáveis para criar dump e restore de bases de dados PostgreSQL?

welrbraga@weldesk:~$ which pg_restore
/usr/bin/pg_restore
welrbraga@weldesk:~$ which pg_dump
/usr/bin/pg_dump

Exemplo 2: Regra com usuário substituto diferente do root

Aproveitando o caminho dos comandos de backup do postgresql que descobrimos acima, segue abaixo uma regra que permite ao usuário daniel invocar os comandos de dump e restore, como se fosse o usuário postgres:

daniel  weldesk  = (postgres) /usr/bin/pg_restore, /usr/bin/pg_dump, /usr/bin/whoami 

Comparado ao exemplo anterior, há uma diferença sutil porém importante aqui. Como já dito, o usuário substituto default é o “root”, sendo assim, quando nós executamos qualquer comando com o “sudo” sem informar este argumento, o sudo tentará executar o comando pedido como “root” (vide o “Exemplo 1”).

Neste exemplo o usuário substituto não é o “root”, mas o “postgres”. Sendo assim, se o usuário “daniel” tentar executar estes comandos sem informar o usuário substituto (“postgres”) ele não será autorizado.

Propositalmente eu adicionei o comando “whoami” (que apenas exibe o nome do usuário logado) para podermos fazer um teste rápido. Acompanhe.

Compare as três saídas abaixo em que o usuário tentou executar o comando “whoami”.

daniel@weldesk:~$ whoami
daniel
daniel@weldesk:~$

daniel@weldesk:~$ sudo whoami
Sinto muito, usuário daniel não tem permissão para executar "/usr/bin/whoami" como root em weldesk.
daniel@weldesk:~$

daniel@weldesk:~$ sudo -u postgres whoami
postgres
daniel@weldesk:~$

No primeiro teste ele executou o comando diretamente e obteve como retorno o seu nome corretamente; no segundo, ele tentou usando o sudo sem informar com qual usuário (o que forçou o usuário default – “root”) o qual não foi permitido, já que é regra deste exemplo só é satisfeita com o usuário “postgres”, o que pode ser observado no terceiro teste que exibiu corretamente o nome do usuário que executou o comando.

O mesmo se aplicaria aos outros dois comandos informados na regra que escrevemos, de forma que seria obrigatório o usuário informar que executará os comandos pedidos com o usuário “postgres”, ou seja:

sudo -u postgres pg_dump ....
sudo -u postgres pg_restore ...

Sem informar o “-u postgres” estes comandos não seriam executados como esperado.

Exemplo 3: Regra que libera tudo para todos em qualquer lugar

Quando comentei sobre a estrutura das regras eu mencionei a palavra chave “ALL” que indica “tudo” naquele contexto onde ela foi empregada.

Esta não é uma regra recomendada, mas é um pouco melhor do que definir uma senha para o usuário root e sair distribuindo entre seus usuários.

daniel ALL = (ALL) ALL

Isso permitirá que o daniel, partir de qualquer máquina, execute qualquer comando como qualquer usuário.

Caso seja necessário fazer uma regra como esta para muitos usuários, o melhor a fazer seria incluí-los como membros de um grupo específico e depois aplicar a regra apenas ao grupo.

Ou seja, ao invés disso:

daniel ALL = (ALL) ALL
ricardo ALL = (ALL) ALL
marcos  ALL = (ALL) ALL

Adicionamos os três usuários a um grupo qualquer (por exemplo o grupo “sudo”) com o comando “adduser” e depois criamos uma regra como:

%sudo ALL=(ALL:ALL) ALL

Perceba o uso do símbolo “%” a frente da palavra “sudo” para identificar que estamos nos referindo ao “grupo sudo” e não ao “usuário sudo”.

Este grupo pode ter qualquer nome, mas fica aqui registrada a dica que em algumas distribuições já temos o grupo “sudo” e esta regra pronta no arquivo /etc/sudoers, bastando apenas incluir os seus usuários neste grupo (com o comando adduser) para que eles possam usar os privilégios administrativos nesta máquina.

# adduser daniel sudo
# adduser ricardo sudo
# adduser marcos sudo

Em alguns casos a regra para o grupo “sudo” poderá estar comentada naquele aquivo (com o símbolo “#” a frente), bastaria então descomentá-la, como passo adicional e pronto.

Exemplo 4: Com senha ou sem senha

Se você já usou o “sudo” algumas vezes, deve ter notado que nem sempre ele pede a sua senha.

Isso ocorre porque o “sudo” registra o momento que a senha foi pedida e só a pedirá novamente em duas situações:

  1. se passar mais de quinze minutos sem invocar o sudo novamente, ou
  2. após invoca-lo com o argumento “-k / –reset-timestamp” (ex: “sudo -k”) para invalidar o arquivo de marcação de tempo.

Mas além disso, em alguns casos pode ser interessante que certos comandos sejam executados sem necessidade de um pedido de senha e para isso basta marcarmos estes comandos com as tags “NOPASSWD” e “PASSWD”.

No exemplo a seguir temos uma cópia da mesma regra usada no “exemplo 1”, porém acrescida das tags em questão:

daniel  weldesk  = (root) /usr/bin/cat, NOPASSWD:/usr/bin/ls

Desta forma quando o usuário daniel usar o comando “sudo ls” nunca lhe será feito qualquer pedido de senha, entretanto ao usar o comando “sudo cat”, sim.

É importante observar que a tag “PASSWD” é o padrão quando não informada, por isso não o informamos na linha acima, mas poderíamos se quiséssemos. Deixando a regra assim:

daniel  weldesk  = (root) PASSWD:/usr/bin/cat, NOPASSWD:/usr/bin/ls

Outro ponto a destacar sobre estas tags é que elas são herdadas pelos comandos seguintes a sua declaração. Isso significa que se tivéssemos mais algum comando após a declaração do “cat” ele pediria a senha antes da execução, no entanto se estivesse depois do “ls” ele nunca pediria a senha.

daniel  weldesk  = (root) PASSWD:/usr/bin/cat, /usr/bin/less, NOPASSWD:/usr/bin/ls, /usr/bin/md5sum

No exemplo acima o novo comando “less” pedirá senha tal como o “cat”, enquanto o “md5sum”, nunca pedirá, assim como o “ls”.

Desta forma é importante estar atento a ordem dos comandos e as tags, pois em uma inversão você poderia se confundir e autorizar o uso de comandos sem senhas quando na verdade deveria ser o contrário.

Na dúvida, faça a configuração em “modo desespero” ou “modo plantão da madrugada”. Quando o sono está te matando e você não encontra a razão pelo que a regra bonitinha e estruturada não funciona, parta para a solução mais fácil e separe tudo em regras independentes.

daniel  weldesk  = (root) NOPASSWD:/usr/bin/ls, /usr/bin/md5sum
daniel  weldesk  = (root) /usr/bin/cat, /usr/bin/less

Embora isso possa parecer estúpido … na verdade é! É uma das recomendações da filosofia Linux: KISS (Keep It Simple Stupid), afinal de contas funcionando é melhor do que não funcionando.

Uma palavra sobre segurança

Há um propósito muito elementar para a necessidade do usuário digitar uma senha antes de executar um comando administrativo. E este propósito chama-se “segurança”.

Talvez você saiba que não deve digitar comandos como “mkfs”, “rm” ou até mesmo o “cat” à revelia em seu sistema, mas imagine que um usuário inexperiente tenha acesso a sua máquina e resolva experimentá-los!

Se você está ciente dos riscos e sabe proteger o seu sistema de outras maneiras, incluindo mas não se limitando a, não compartilhar sua senha e nem manter sua sessão aberta enquanto você está distante do terminal, então você pode ir em frente.

Esteja ciente de que ao usar a tag NOPASSWD, você pode estar removendo uma importante camada de segurança do seu sistema e em alguns casos o tamanho do desastre pode ser imensurável.

Exemplo 5: Usando alias para agrupar usuários, comandos e hosts

Não confunda aqui os aliases do sudo com os grupos de usuários sistema.

Nós já vimos (no exemplo 3) o uso de grupos de usuários do sistema, mas os “aliases” do sudo fazem muito mais do que apenas agrupar usuários.

O sudo permite a definição de “alias” para agruparmos logins, comandos, máquinas etc, levando a organização de nossas regras à outro nível.

Particularmente o mais útil, é o grupo de comandos, que veremos a seguir, permitindo que tenhamos várias regras que usem os mesmos comandos sem ter que digitá-los diversas vezes, mas se bem usados, todos os outros serão igualmente útil.

Agrupando comandos

Digamos então que tenhamos um conjunto de usuários que apenas administre o firewall da máquina e que os comandos que este grupo utilizam são “fail2ban-client , iptables , iptables-save , iptables-restore”.

Nós podemos ter um grupo de sistema chamado “secadmin” com todos os usuários que poderão executar aqueles comandos durante suas atividades na máquina e então criarmos uma regra assim:

%secadmin ALL = (root) /usr/bin/fail2ban-client , /usr/sbin/iptables , /usr/sbin/iptables-save , /usr/sbin/iptables-restore

Veja agora como fica a alternativa usando alias para os comandos:

Cmnd_Alias CMD_FIREWALL = /usr/bin/fail2ban-client , /usr/sbin/iptables , /usr/sbin/iptables-save , /usr/sbin/iptables-restore

%secadmin ALL = (root) CMD_FIREWALL

Com os comandos agrupados no alias CMD_FIREWALL, se precisarmos atribuir estes mesmo comandos a outro grupo ou usuário fora do grupo “secadmin”, nós não teríamos que digitar todos os comandos novamente.

automacao ALL = (root) NOPASSWD: CMD_FIREWALL

Agrupando usuários

Se quisermos podemos até mesmo substituir o grupo de sistema “secadmin” por um alias de usuários chamado “USR_SECURITY”, deixando a regra assim:

Cmnd_Alias CMD_FIREWALL = /usr/bin/fail2ban-client , /usr/sbin/iptables , /usr/sbin/iptables-save , /usr/sbin/iptables-restore

User_Alias USR_SECURITY = rafael, tiago, dani

USR_SECURITY ALL = (root) CMD_FIREWALL
automacao ALL = (root) NOPASSWD: CMD_FIREWALL

E qual foi a vantagem de substituir o grupo do sistema “secadmin” pelo alias “USR_SECURITY” ? Ao usar alias, você não precisa que o responsável por definir permissões tenha também privilégio para usar os comandos “adduser” e “addgroup” do sistema.

Nestes exemplos talvez pareça que não houve vantagem em ter uma linha a mais apenas para colocar os comandos ou mesmo os usuários agrupados, mas se pegarmos este último conjunto de regras e substituirmos os alias CMD_FIREWALL e USR_SECURITY pelos respectivos comandos e usuários nas duas regras que temos, você observará que ficará confuso lidar com elas.

Imagine o caos que seria se tivéssemos outra dúzia de regras usando estes mesmo comandos e sem aliases. Atualizar todas elas adicionando mais alguns comandos em todas elas seria uma tarefa no mínimo cansativa aos olhos!

Veja abaixo um exemplo mais complexo com três alias e tente imaginar a bagunça que seria se em todas as regras nós escrevêssemos todos os comandos em cada regra:

# Alias de Comandos
Cmnd_Alias CMD_FIREWALL = /usr/bin/fail2ban-client , /usr/sbin/iptables , /usr/sbin/iptables-save , /usr/sbin/iptables-restore
Cmnd_Alias CMD_PKG = /usr/bin/apt , /usr/bin/aptitude , /usr/bin/dpkg , /usr/bin/apt-get
Cmnd_Alias CMD_MONITOR = /usr/sbin/iotop , /usr/bin/htop

# Permissoes
pedro ALL=(root) NOPASSWD: CMD_PKG
welrbraga ALL=(root) NOPASSWD: CMD_FIREWALL, CMD_PKG, CMD_MONITOR
daniel ALL=(root) CMD_FIREWALL, NOPASSWD: CMD_PKG, CMD_MONITOR

Antes de continuar, observe que em todos os exemplos eu usei os nomes de alias escritos com letras MAIÚSCULAS. Sim, isso é uma regra.

Agrupando hosts

Até aqui eu usei a palavra chave “ALL” no campo host/máquina e para a maioria das situações isso basta. No entanto isso implica no fato de que para cada máquina que administramos, nós teremos que criar um arquivo de regras para o sudo.

Se soubermos como usar este campo corretamente, nós poderemos manter um único arquivo salvo em algum repositório centralizado e que será replicado a todas as máquinas que nos interessam afetando todas elas de uma só vez.

Com isso poderíamos manter apenas um único arquivo em um repositório Git, FTP, SFTP, Rsync, Webdav, HTTP etc que será copiado periodicamente para as máquinas, ou ainda usar uma ferramenta de orquestração como Ansible, Puppet etc para transferir o arquivo a todas as máquinas sem se preocupar com outras validações além da sintaxe das regras.

Vamos imaginar então que eu tenha um grupo de administradores de firewall que precisarão acessar somente o servidor firewall/proxy; um grupo de administradores de banco de dados que acessarão apenas o servidor de banco de dados, e um grupo de administradores gerais que acessarão alguns serviços em todos os servidores.

Teríamos então um arquivo sudoers como segue:

# Atenção, não altere este arquivo diretamente
# Este arquivo é mantido a partir do diretório web no endereço https://intranet.exemplo.com/regrasudo.txt
#

# Alias de Comandos
Cmnd_Alias CMD_FIREWALL = /usr/bin/fail2ban-client , /usr/sbin/iptables , /usr/sbin/iptables-save , /usr/sbin/iptables-restore
Cmnd_Alias CMD_PKG = /usr/bin/apt , /usr/bin/aptitude , /usr/bin/dpkg , /usr/bin/apt-get
Cmnd_Alias CMD_MONITOR = /usr/sbin/iotop , /usr/bin/htop
Cmnd_Alias CMD_POSTGRES = /usr/bin/pg_dump, /usr/bin/pg_restore

# Alias de usuários
User_Alias USR_SECURITY = rafael, tiago, daniel
User_Alias USR_DATABASE = rafael, cristiano
User_Alias USR_GERAL = marcela

# Alias de hosts
Host_Alias HOST_SISTEMA = firewall1, dbserver1

# Regras
USR_SECURITY firewall1 = (root) CMD_FIREWALL
USR_DATABASE dbserver1 = (postgres) CMD_POSTGRES
USR_GERAL HOST_SISTEMA = (root) CMD_PKG, NOPASSWD: CMD_MONITOR

Observe com atenção a seção de regras neste arquivo. Observe que eu nomeei os hosts firewall1 e dbserver1. Isso significa dizer que aquelas regras só funcionarão nos hosts com estes nomes.

Ou seja, rafael, tiago e daniel só poderão usar os comandos de administração de firewall na máquina “firewall1”, rafael e cristiano só poderão fazer dump e restore da base PostgreSQL no servidor “dbserver1” e a marcela poderá atualizar e monitorar o sistema em ambas as máquinas.

Se o arquivo estiver em uma máquina com qualquer outro nome que não aqueles mencionados ali (firewall1 e dbserver1), as suas regras não serão validadas e os usuários não terão permissão para executar estes comandos.

Com este arquivo salvo na minha máquina, eu poderia enviá-lo para todos meus servidores, pois as permissões terão efeito apenas nas máquinas que foram definidas ali.

A vantagem é manter o controle de permissões de acesso centralizado e visível de um único lugar. Note no exemplo, que eu deixei um comentário informando sobre o local onde está o arquivo original a ser alterado para o caso de outra pessoa precisar alterar o arquivo.

Agrupando usuários substitutos

Com isso, de todos os alias possíveis de se usar no sudo, o único que faltou foi o Runas_Alias que mantém uma lista de usuários substitutos.

Em geral nós precisamos do sudo para executar determinado comando com um único usuário.

Mas se você tiver a necessidade de uma regra em que o usuário possa executar determinado comando com duas opções de usuário alternativo? Veja:

Runas_Alias RUN_MONITOR = apache2, postgres
welington ALL = (RUN_MONITOR) /usr/bin/top, /usr/bin/htop

A regra acima permite que o usuário welington possa executar os comandos top e htop tanto com os privilégios do usuário apache2 quanto com os privilégios do usuário postgres, como nos exemplos abaixo:

sudo -u apache2 htop
sudo -u postgres htop

O comando htop permite não só visualizar os processos em execução, como também controlar e matar os processos do usuário.

Nestes casos então, o usuário “welington” pode matar os processos do apache e do postgres, se necessário, sem comprometer os processos dos demais usuários.

Isso é pouco usado, mas o recurso está disponível caso precisemos.

Executando comandos com sudo remotamente

Se você costuma se conectar via ssh para executar algum comando e sair em seguida, esta dica é para você.

Normalmente nós nos conectamos por ssh e mantemos a sessão aberta para executar várias atividades, mas é sabido que podemos apenas digitar um só comando e sair assim:

ssh meuservidorweb 'df -h'

Isso conectaria ao meuservidorweb, executaria o comando “df -h” e retornaria ao meu computador. Isso é um recurso útil em scripts onde precisamos consultar ou mesmo modificar uma única informação naquela máquina e mais nada.

No entanto, se o comando que você precisa executar requer privilégios via “sudo”, existe uma pegadinha (no ssh) que você precisa resolver.

O comando abaixo não funciona porque o usuário comum não possui permissão de ver o arquivo pedido

ssh meuservidorweb "cat /etc/shadow"
cat: /etc/shadow: Permissão negada

O comando abaixo não funciona porque o sudo, não funciona corretamente via SSH:

ssh meuservidorweb 'sudo cat /etc/shadow'
sudo: no tty present and no askpass program specified

Há duas soluções possíveis para isso:

  1. Ou nós damos permissão via sudoers para que nosso usuário possa executar pelo menos o comando “cat” sem o uso de senhas ( com a tag NOPASSWD, vide o exemplo 4);
  2. Ou nós podemos solicitar ao SSH para criar o TTY reclamado pelo sudo usando um único argumento (-t) na linha de comandos:
ssh -t meservidorweb 'sudo cat /etc/shadow'
[sudo] password for welington: 
root:$6$aXf/iPD4$Vrly7.LLK7wR9Ryl5Gm3zB65vRcQcs4MJekavN3u/98fDF86YsSk7EtdXh5kNE.ieUTIqhDkG4bkdZBF9NwUa1:16931:0:99999:7:::
daemon:*:15605:0:99999:7:::
bin:*:15605:0:99999:7:::
sys:*:15605:0:99999:7:::

Alguns parâmetros importantes / úteis

Nos exemplos acima eu mostrei o uso do sudo normalmente seguido do “-u” para especificar o usuário substituto, mas há outros argumentos que você deveria conhecer.

Alguns deles são:

-v ou –validate = Se lembra que eu disse que a sessão do sudo é de 15 minutos? Se o tempo estiver acabando e você não quer ter que digitar a senha novamente, antes que o tempo acabe, digite “sudo -v” para renovar o seu tempo

-k ou –reset-timestamp = Ainda relacionado ao seu tempo de 15 minutos, se você precisar esgotá-lo de imediato basta digitar “sudo -k”. Isso pode ser útil se precisar ceder o seu terminal para algum usuário e você acabou de usar o sudo, desta forma se ele tentar se aproveitar das suas credenciais para fazer besteira, ele não conseguirá (cuidado aos comandos que você tirou a barreira de senha)

-l ou –list = Para vermos as regras do sudo que se aplicam ao nosso usuário podemos digitar “sudo -l”. Elas serão listadas de forma estruturada na nossa tela para apreciação e consulta.

-U ou –other-user = Ainda falando de listar regras, podemos ver as regras válidas para outro usuário que não o nosso acrescentando esta chave seguida do login a ser analisado, assim: “sudo -l -U daniel” (perceba que este é um complemento do “–login”).

Claro que há muitos outros e recomendo a leitura do manual (man sudo), estes são os que uso com relativa frequência e creio que sejam úteis para mais pessoas.

Recursos adicionais não mencionados

O sudo é uma ferramenta de controle de acesso incrível e com bastante recursos pouco explorados pelos seus usuários. Embora eu não tenha mencionado, só para aguçar a curiosidade, entre as muitas facilidades que ele nos oferece, temos os seguintes recursos que eu não mencionei neste texto (talvez o faça em um futuro texto de complemento):

  • Os comandos podem ser assinados, de forma que possam estar em uma pasta gravável pelo usuário, pois mesmo que o usuário altere o arquivo por outro, o sudo identifique a violação e não autorize que o comando seja executado;
  • É possível usarmos caracteres curingas (*?[] etc) para limitar o uso de comandos a um grupo especifico de arquivos, por exemplo, digamos que há um acervo de arquivos cujos nomes são prefixados com determinado código e algumas pessoas precisam executar as mesmas atividades mas apenas com os arquivo que tiverem determinado prefixo;
  • Limitar o período em que uma determinada regra é válida – útil para que as regras de um usuário temporário sejam revogadas na data de sua saída, desta forma, mesmo que suas regras não sejam removidas, por qualquer motivo, elas serão invalidadas;
  • Alertar por e-mail ou registrar em arquivo de log, cada vez que um usuário invocar o sudo

Por hora é só. Aproveitem o novo conhecimento, caso seja novidade para você, e compartilhe algum uso diferente, caso seja interessante e até a próxima.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.