Qual é uma boa configuração que permite a execução automática de um comando ou script em um servidor remoto com root
privilégios usando SSH?
Estou ciente (apenas vagamente para algumas opções) das seguintes opções:
- Permitindo um login direto por
root
(PermitRootLogin
) (e possivelmente forçando autenticação de chave). - Configurando
sudo
para não exigir senha (NOPASSWD
flag insudoers
) e TTY (requiretty
flag). - Configurando
sudo
para permitir a execução de comandos/scripts específicos, quando autenticados com uma chave privada específica. - Definindo o proprietário do script como
root
e configurando a permissão setuid .
Mas, primeiro, não tenho certeza de quais são as consequências de segurança disso. Por exemplo, eu sei que permitir o root
login é desaprovado. Mas não tenho certeza, se esse não for um ponto de vista obsoleto. Pelo que entendi, parece que uma autenticação de senha é o perigo. Com autenticação de chave pública, o root
login direto pode estar ok. E para algumas das opções, principalmente o sudo
, não tenho certeza nem sobre a configuração necessária. Embora eu seja capaz de pesquisar tudo isso no Google, pode haver considerações de segurança que posso perder, é por isso que estou pedindo a opinião de especialistas.
Observe que estou solicitando uma configuração do lado do servidor . A execução será acionada por um programa, não por uma ferramenta como ssh
, portanto, não estou procurando coisas como autenticação automática do cliente .
Histórico: Estar ativo em ssh
tag no Stack Overflow , uma das perguntas frequentes que surgem, são sobre vários hacks que as pessoas tentam, ao tentar executar um comando/script (ou mesmo um servidor SFTP) sobre um SSH em um Unix/Linux remoto servidor servidor usando uma root
conta usando várias linguagens de programação (C#, Java, VB.NET, Python, etc.) e bibliotecas SSH (SSH.NET, JSch, Paramiko, etc.).
As implementações, que as pessoas tentam, geralmente tentam usar su
ou sudo
. Estes, então, solicitam uma senha. Portanto, as implementações tentam alimentar a senha para a entrada do comando. Como su
muitas sudo
vezes exigem emulação de terminal para o prompt de senha, a implementação precisa exigir PTY. O que, por sua vez, causa mais problemas, pois as sessões com a emulação de terminal geralmente empregam recursos interativos, como códigos de escape ANSI , paginação etc. terminal suficiente para evitar a paginação.
Alguns exemplos de muitos:
- O comando “sudo” executado com JSch requer senha, mesmo quando a senha não é necessária em uma sessão SSH interativa
- Obtendo “deve ser executado a partir de um terminal” ao alternar para o usuário root usando o módulo Paramiko em Python
- Executando o comando usando “su -l” no SSH usando Python
- Usando JSch para SFTP quando é preciso também trocar de usuário
Embora eu geralmente possa fornecer ajuda na implementação desses hacks, também costumo adicionar uma sugestão de que existem maneiras melhores do que automatizar sudo
/ su
. Mas não estou realmente confiante em fornecer detalhes dessas supostas "melhores maneiras" . Uma pergunta relacionada: é sudo
quase inútil?
Portanto, estou procurando uma resposta canônica de uma perspectiva de superusuário, que pode ser referenciada e adaptada para fins de estouro de pilha.
Acredito que uma solução apropriada para a maioria dos casos simples [ou seja, se uma estrutura como Puppet/Chef/CfEngine/Ansible for um exagero], mas é necessário um alto nível de controle do sistema remoto para
(a) Exigir autenticação baseada em chave (b) bloquear os locais que podem ser usados pelo SSH - particularmente para bloquear os endereços IP que os usuários root podem usar (c) Garantir que as máquinas com essa relação de confiança estejam devidamente protegidas.
Não acredito que "fazer login como root seja desaprovado", tanto quanto "fazer login como root para fazer coisas que não requerem permissões de root" é desaprovado. Ter uma senha fácil de adivinhar torna possível que a conta seja forçada bruta, de modo que é um problema a ser enfrentado e, ao permitir que as pessoas façam login como root, elas podem cometer erros estúpidos com um escopo mais amplo e fazer coisas questionáveis que ocultam atividade maliciosa - mas, dependendo da arquitetura, isso pode não ser realmente significativo.
Este quadrinho do XKCD aponta que, dependendo do ambiente, pode não importar se uma conta root está comprometida.
Provavelmente, a solução mais simples e eficaz para o caso geral é limitar exatamente quem pode efetuar login como root , controlando as chaves em conjunto com a especificação de uma linha AllowUsers apropriada em /etc/ssh/sshd.conf. Uma linha apropriada para permitir usuários normais, mas bloquear o acesso root pode ser semelhante a:
Claro, é importante que o login baseado em senha não seja permitido, ou que a conta root não tenha uma senha (ou seja, tenha um "!" ou "*" no campo de senha do arquivo de senha.)
Como você postulou, se apenas um único (ou pequeno número de) programa (s) precisarem ser executados, talvez seja melhor configurar um usuário específico com autenticação baseada em chave e permitir o acesso sudo apropriado aos comandos necessários.
Há, é claro, muitas coisas que podem ser feitas para "bloquear" o acesso ainda mais, dependendo do valor dos dados - selinux, registro remoto, shell limitado, restrições de horário do dia, notificações imediatamente nos logins , monitoramento de log ativo como fail2ban [além das restrições de rede que considero não opcionais] podem fazer parte de uma solução. Dito isso, se você está simplesmente controlando um sistema que pode ser detonado e recriado facilmente, muito disso provavelmente é um exagero.
Lembre-se de que a segurança é construída em camadas, para poder obter acesso root, uma conta deve passar por várias camadas. Bloquear o acesso, chaves privadas SSH, firewalls, restrições de hora do dia [e princípio do menor acesso, ou seja, fornecer acesso apenas ao que é necessário, não mais, registro, backups] devem funcionar juntos como parte de uma boa segurança.
Adicional - acesso SUDO
Sudo é um mecanismo para permitir que um usuário regular execute determinados comandos com acesso elevado e é bastante flexível e variado em escopo. Embora um resumo do sudo não seja apropriado aqui (mas está bem documentado se você digitar man sudo na maioria das distribuições, as etapas apropriadas podem ser -
Editar /etc/sudoers - A maioria das variantes do Linux tem um programa especial para fazer isso chamado "visudo" que precisa ser executado como root e aproximadamente equivalente a usar o editor do sistema para editar /etc/sudoers (que é outra maneira de fazer isso - embora provavelmente ao redor)
Adicione/altere as linhas apropriadas para permitir que um determinado usuário faça coisas específicas. Se, por exemplo, você quiser que eles possam montar diretórios por exemplo e sem precisar digitar uma senha, digite uma linha como:
Para executar este comando, o usuário apropriado executaria algo como
Você pode listar várias linhas para vários comandos, usar grupos em vez de usar - sudoers é um subsistema bastante flexível. Em muitas distribuições também é possível adicionar arquivos com comandos a um subdiretório como /etc/sudoers.d
A seguir está uma resposta do post Unix Stackexchange
Como executar remotamente o comando ssh um comando sudo sem senha .
Este método permite que o administrador do servidor permita que sua conta execute um comando como
sudo
sem especificar a senha. O comando provavelmente é a chamada para seu script e só é permitido quando executado em sua conta. Como o comando permitido é totalmente especificado incluindo argumentos, acredito que esse método seja bastante seguro.Minha configuração em situação semelhante é
/home/blesseduser/.ssh/authorized_keys
:Dentro desse script, faço alguma limpeza da
SSH_ORIGINAL_COMMAND
variável (além de alguma auditoria) e extraio o comando que o usuário deseja executar. Todos os comandos permitidos estão nos usuários/home/blesseduser/bin
como links simbólicos para/usr/local/bin/sudo-runner
:Os links simbólicos são gerados pelo script do
sudoers
arquivo. Quando nenhum comando está presente, o conteúdo de seubin
diretório é listado. Se você não restringir o encaminhamento de porta, coisas ruins podem acontecer.considerações gerais
Sempre que utilizar SSH, deve-se evitar a autenticação por senha , ou seja, o arquivo /etc/ssh/sshd_config deve conter as seguintes linhas:
No entanto, se alguém - por algum motivo - tiver que usar autenticação por senha , deve-se usar ferramentas estabelecidas, bem conhecidas e testadas, como sshpass . Não comece a canalizar senhas sozinho.
Se estiver usando a autenticação de chave pública , não faz sentido proteger a chave privada por uma frase secreta, se a frase secreta estiver armazenada em um arquivo de configuração ou algo semelhante. Se um invasor conseguir obter acesso de leitura do sistema de arquivos para roubar o arquivo de chave privada, ele também poderá roubar o arquivo de configuração.
Todos os comandos que podem ser executados com privilégios de usuário devem ser executados com privilégios de usuário em vez de root .
A linguagem de programação utilizada não será considerada nesta resposta, pois não há diferença entre Python's
subprocess.call
, Java'sjava.lang.Runtime.exec
ou um ambiente subshell dentro de um shell script no que diz respeito à segurança.Proteger ainda mais o host remoto contra invasores externos configurando um firewall, colocando sistemas IDS/IPS no lugar e similares também não será considerado, pois está fora do escopo.
Dito isso, vamos considerar diferentes cenários:
Executando comandos dos quais um subconjunto finito requer privilégios de root
Deve-se usar um usuário separado (
adduser --shell /bin/rbash --disabled-password remcmdexec
criará um usuário com um shell restrito, incapaz de fazer logins locais, mas apenas remotos, consulteman adduser
eman rbash
) em combinação com um arquivo sudoers que permite que esse usuário execute apenas o conjunto finito e necessário de comandos como root (consulteman sudoers
) no host remoto:Exigir uma senha para executar esses comandos
sudo
não faz sentido, pois o login local foi desativado (--disabled-password
parâmetro) e um invasor que conseguiu roubar o arquivo de chave também poderá obter a senha necessária (consulte a primeira seção da resposta).O arquivo author_keys deve conter mais restrições para evitar, por exemplo, encaminhamento de porta, consulte
man sshd
:Ele também deve pertencer ao root e ser lido, mas não gravável pelo usuário remcmdexec , para evitar a remoção de restrições SSH:
Invoque, por exemplo
ssh remcmdexec@remhost sudo /usr/bin/systemctl reload some.service
, para um comando que requer privilégios de root . Para todos os outros comandos, pulesudo
.Comandos em execução dos quais um subconjunto não finito, mas adequado, requer privilégios de raiz
A mesma configuração apresentada na seção anterior da resposta pode ser usada, mas o arquivo sudoers precisa ser adaptado:
Isso ocorre porque o remcmdexec finalmente precisa obter privilégios de root . Entenda que um invasor que é capaz de fazer login como remcmdexec agora pode remover todas as restrições impostas no host remoto, não importa o quão complexo tenha sido o modo de obter privilégios de root . Portanto, todas essas restrições são inúteis em relação à segurança (um invasor voluntário). No entanto, eles não são fúteis em relação à segurança (falhas do sistema).
Executando um conjunto não finito de comandos, dos quais todos requerem privilégios de root
Não faz mais sentido usar
sudo
. Em vez disso, faça login como um usuário com privilégios de root para executar um comando:ssh root@remhost /usr/bin/somecmd
Portanto, a seguinte linha deve estar presente no arquivo /etc/ssh/sshd_config :
No entanto, mantenha as restrições dentro do arquivo authorised_keys para preservar alguma segurança básica .
Aqui está uma resposta sobre as considerações de segurança, que acho que não foram abordadas nas outras respostas.
Existem várias partes para isso: permitir a execução de um único script ou comando com privilégios elevados (raiz) e usar SSH. Estes não são necessariamente dependentes.
Isso permitirá que qualquer pessoa tenha privilégios de root completos (não restritos ao seu único comando/script). Ele também permitirá que qualquer pessoa tente invadir seu sistema remotamente, tentando senhas, etc.
Isso permitirá que qualquer usuário tenha privilégios totais de root, desde que esteja logado. Em termos de segurança, não é muito melhor do que permitir o login root, embora haja menos tentativas automatizadas de invadir outras contas de usuário.
Não tenho certeza de como isso seria implementado - o sudo não sabe nada sobre as chaves SSH, pelo menos as variantes do sudo com as quais estou familiarizado.
Configurar o sudo para permitir apenas a execução de comandos/scripts específicos é muito melhor do ponto de vista da segurança (porque é mais restritivo).
Isso permitirá que qualquer usuário execute este script como root. Você não pode restringir isso a usuários específicos, e os bits setuid têm seus próprios pontos fracos de segurança em potencial.
No final, não acho que haja uma única resposta canônica - a melhor solução depende de suas circunstâncias e requisitos. Então, como em todas as coisas relacionadas à segurança, primeiro você se senta e define os requisitos: Quão permissivo e flexível você quer ser? Qual é o caso de uso real? Com que firmeza você precisa amarrar o sistema? etc.
Dito isso, deixe-me adicionar uma alternativa muito restritiva que você não mencionou:
Crie uma conta de usuário específica que seja usada apenas para executar esse script/comando específico. Permitir login SSH apenas neste usuário com um par de chaves (desativar senhas). Configure sudo para permitir que este usuário execute o comando particular/script como root.
Isso tem as seguintes consequências de segurança:
Hackers externos não podem quebrar a senha da conta específica usando força bruta.
Qualquer pessoa que tenha acesso a esta conta só poderá executar um único script/comando.
Outros usuários não obtêm privilégios elevados por meio dessa construção.
Sem fraquezas setuid.
Ansible é a melhor ferramenta para automação e em hosts remotos. O uso dos métodos disponíveis do Ansible pode executar os comandos como um superusuário (root) em máquinas remotas
--become & --become_method
para alternar para o root via sudo sem habilitar permissão de login root e NOPASSWD para sudo.Além disso, não há necessidade de instalações em hosts clientes - o único requisito é que os hosts remotos suportem Python >= 2.7.
AFAIK Ansible tem dois métodos de acesso, um é com SSH e Paramiko.