Por que meu tar via ssh (comando via authorized_keys) corrompe o arquivo?

1

De uma máquina de backup, eu quero extrair tgz dumps de um servidor de produção. Ambas as máquinas executam o Ubuntu 16.04.

Portanto, o servidor de backup se conecta via ssh e um ssh específico ao servidor de produção.

O arquivo ~/.ssh/authorized_keys do respectivo usuário no servidor de produção deve permitir apenas um único comando e colocar o máximo de restrições possível (espero):

command="tar -cz --file - --ignore-command-error --ignore-failed-read /dir/ 2>/dev/null | cat",no-agent-forwarding,no-port-forwarding,no-user-rc,no-X11-forwarding ssh-rsa AABLASHKEY comment

onde /dir/ é o diretório do backup, AABLASSHKEY e comment são os valores "reais", é claro.

O | cat é necessário neste caso porque de outra forma o tar nessa versão do Ubuntu ("tar (GNU tar) 1.28") não irá falar com o stdout dado pelo ssh (PTY). O stderr deve ir para o vazio ( 2> /dev/null ). Editar : O ponto sobre o PTY é um equívoco, veja a resposta por @grawity.

No lado de recebimento (o backup server), eu o peguei da seguinte forma:

ssh -i /path/to/key the-user@production-server > dir.tgz

No entanto, o arquivo resultante difere em tamanho do arquivo se eu craquetá-lo no servidor e não é um arquivo válido (por exemplo, gzip: stdin: invalid compressed data--crc error ... gzip: stdin: invalid compressed data--length error ). A diferença de tamanho é de 22 bytes.

Se eu permitir que o servidor de backup execute qualquer comando no servidor produtivo, removendo as restrições em authorized_keys , tudo funcionará bem. De que ponto eu sinto falta?

Restrições

  • Eu realmente quero usar tar (não rsync, rrsync ou algo parecido).
  • A conexão deve ser iniciada pelo servidor de backup
  • O servidor de produção não deve criar arquivos temporários

Solução

Como @Grawity apontou em sua resposta (leia-a para esclarecer alguns equívocos), a linha seguinte em ~.ssh/authorized_keys resolve o problema (e funciona no Ubuntu 16.04 com a versão do OpenSSH):

command="tar -cz --file - --ignore-command-error --ignore-failed-read /dir/ 2>/dev/null",restrict ssh-rsa ....

Para fazer com que o comando de back-up do servidor não emita nenhum aviso, conecte-se com:

ssh -o RequestTTY=no -i /path/to/key the-user@production-server > dir.tgz
    
por Felix 09.10.2018 / 10:28

1 resposta

3

The | cat is needed in this case because otherwise tar […] will not speak to the stdout given by ssh (PTY).

Não. Ter um PTY é precisamente um dos seus problemas. A camada tty existe para processar caracteres de controle de terminal e não é algo que você queira em todos os para outros tipos de dados.

Normalmente em execução ssh no modo de lote (ou seja, ssh <host> <cmd> ) não alocará um lado do servidor PTY; Ele fornecerá um canal limpo de 8 bits. Mas quando você não fornece um comando no cliente, você precisa adicionar explicitamente a opção -T ou RequestTTY client para desativar a solicitação TTY,

ssh -T theuser@prod > dir.tgz
ssh -o RequestTTY=no theuser@prod > dir.tgz

ou forneça um comando fictício,

ssh theuser@prod foo > dir.tgz

ou proibir essas solicitações com a opção no-pty authorized_keys:

command="tar -czf - /dir/ 2>/dev/null",no-pty,restrict ssh-rsa ABCDEF

( restrict é um alias adicionado recentemente que desativa todos os reencaminhamentos de uma só vez, incluindo aqueles que podem ser adicionados no futuro. Está disponível em OpenSSH 7.2 . Inclusive, inclusive inclui no-pty , mesmo que eu o tenha listado separadamente para esta resposta.

    
por 09.10.2018 / 10:41