pexpect и ssh: как отформатировать строку команд после su - root -c - PullRequest
3 голосов
/ 03 февраля 2012

Я пытаюсь перебрать список серверов и паролей, чтобы изменить конфиги sshd на группе серверов, чтобы я мог входить / запускать команды через root с использованием SSH-ключей без пароля.

Я могу это сделатьлегко в bash, но я пытаюсь изучить Python и (очевидно) хотел бы отказаться от ввода паролей вручную.

Вот что я хочу сделать:

scp ~/.ssh/id_rsa.pub /etc/ssh/sshd_config USER@IP:/tmp/

ssh -o StrictHostKeyChecking=no -t USER@IP "su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\""

Iя уже близко подошел к этому в Python с помощью pexpect:

import pexpect

USER="user"
HOST="192.168.1.1"
USERPASS="userpass" 
ROOTPASS="rootpass"

COMMAND1="scp /Users/user/.ssh/id_rsa.pub /Users/user/github/ssh-pexpect/sshd_config %s@%s:/tmp/" % (USER, HOST)

COMMAND2="ssh -o StrictHostKeyChecking=no -t %s@%s \"su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\"\"" % (USER, HOST)

child = pexpect.spawn(COMMAND1)
child.expect('password:')
child.sendline(USERPASS)
child.expect(pexpect.EOF)
print child.before

child = pexpect.spawn(COMMAND2)
child.expect('password:')
child.sendline(USERPASS)
child.expect('Password:')
child.sendline(ROOTPASS)
child.expect(pexpect.EOF)
print child.before

Когда я запускаю эту команду COMMAND1 (scp'ing) работает нормально.Но COMMAND2 дает сбой:

server1:ssh-pexpect user$ python test4.py 

id_rsa.pub                                    100%  410     0.4KB/s   00:00    
sshd_config                                   100% 3498     3.4KB/s   00:00    

Traceback (most recent call last):
  File "test4.py", line 25, in <module>
    child.expect(pexpect.EOF)
  File "/Library/Python/2.7/site-packages/pexpect.py", line 1316, in expect
    return self.expect_list(compiled_pattern_list, timeout, searchwindowsize)
  File "/Library/Python/2.7/site-packages/pexpect.py", line 1330, in expect_list
    return self.expect_loop(searcher_re(pattern_list), timeout, searchwindowsize)
  File "/Library/Python/2.7/site-packages/pexpect.py", line 1414, in expect_loop
    raise TIMEOUT (str(e) + '\n' + str(self))
pexpect.TIMEOUT: Timeout exceeded in read_nonblocking().
<pexpect.spawn object at 0x102b796d0>
version: 2.4 ($Revision: 516 $)
command: /usr/bin/ssh
args: ['/usr/bin/ssh', '-o', 'StrictHostKeyChecking=no', '-t', 'user@192.168.1.1', 'su - root -c chown', 'root:root', '/tmp/id_rsa.pub;', 'chmod', '600', '/tmp/id_rsa.pub;', 'chown', 'root:root', '/tmp/sshd_config;', 'mkdir', '/root/.ssh;', 'chown', 'root:root', '/root/.ssh;', 'chmod', '700', '/root/.ssh;', 'mv', '/tmp/id_rsa.pub', '/root/.ssh/authorized_keys;', 'mv', '/tmp/sshd_config', '/etc/ssh/;', 'service', 'sshd', 'reload']
searcher: searcher_re:
    0: EOF
buffer (last 100 chars): : Permission denied
mv: try to overwrite `/etc/ssh/sshd_config', overriding mode 0600 (rw-------)? 
before (last 100 chars): : Permission denied
mv: try to overwrite `/etc/ssh/sshd_config', overriding mode 0600 (rw-------)? 
after: <class 'pexpect.TIMEOUT'>
match: None
match_index: None
exitstatus: None
flag_eof: False
pid: 3612
child_fd: 4
closed: False
timeout: 30
delimiter: <class 'pexpect.EOF'>
logfile: None
logfile_read: None
logfile_send: None
maxread: 2000
ignorecase: False
searchwindowsize: None
delaybeforesend: 0.05
delayafterclose: 0.1
delayafterterminate: 0.1

Если я удалю файл / etc / ssh / sshd_config на удаленном сервере перед запуском скрипта, я получу:

server1:ssh-pexpect user$ python test4.py  
id_rsa.pub                                    100%  410     0.4KB/s   00:00    
sshd_config                                   100% 3498     3.4KB/s   00:00    


chown: missing operand
Try `chown --help' for more information.
chown: changing ownership of `/tmp/sshd_config': Operation not permitted
mkdir: cannot create directory `/root/.ssh': Permission denied
chown: cannot access `/root/.ssh': Permission denied
chmod: cannot access `/root/.ssh': Permission denied
mv: accessing `/root/.ssh/authorized_keys': Permission denied
mv: cannot move `/tmp/sshd_config' to `/etc/ssh/sshd_config': Permission denied
bash: service: command not found
Connection to 192.168.1.1 closed.

Я даже не уверенкак отладить это, чтобы увидеть, где все портится.Я не думаю, что он анализирует COMMAND2 правильно, хотя.Довольно плохо знаком с Python, поэтому любые советы приветствуются.Спасибо.

Ответы [ 2 ]

3 голосов
/ 03 февраля 2012

У вас есть КОМАНДА2 в двойных кавычках, и вы корректно экранируете все встроенные двойные кавычки, но вам также нужно дважды экранировать все уже экранированные двойные кавычки. Другими словами, это не проблема Python. Вы можете переключиться на тройные кавычки Python для самых внешних кавычек. Это было бы легче читать.

Редактировать: На самом деле подойдет любое правильное устранение неоднозначности. Поскольку оболочка также предлагает одинарные кавычки, ваше решение с одинарными кавычками вполне подойдет. Python позволит вам использовать одинарные кавычки или ряд других возможностей цитирования, что я бы порекомендовал, если вы еще не решили проблему (потому что тогда вы можете выбирать кавычки, которые не требуют никаких изменений в самой строке; меньше места за ошибку).

Итак, все это должно быть хорошо:

COMMAND2='ssh -o StrictHostKeyChecking=no -t %s@%s "su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\""' % (USER, HOST)

COMMAND2="""ssh -o StrictHostKeyChecking=no -t %s@%s "su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\"" """ % (USER, HOST)

COMMAND2="ssh -o StrictHostKeyChecking=no -t %s@%s 'su - root -c \"chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload\"'" % (USER, HOST)

Мне нужно было добавить пробел к тройным кавычкам, чтобы устранить неоднозначность в соседних двойных кавычках. Но вместо этого вы можете использовать тройные одинарные кавычки. Кроме того, тройные кавычки (одинарные или двойные) позволяют вставлять новые строки, что значительно улучшает удобочитаемость:

COMMAND2='''ssh -o StrictHostKeyChecking=no -t %s@%s "su - root -c '
    chown root:root /tmp/id_rsa.pub
    chmod 600 /tmp/id_rsa.pub
    chown root:root /tmp/sshd_config
    mkdir /root/.ssh
    chown root:root /root/.ssh
    chmod 700 /root/.ssh
    mv /tmp/id_rsa.pub /root/.ssh/authorized_keys
    mv /tmp/sshd_config /etc/ssh/
    service sshd reload'"''' % (USER, HOST)
1 голос
/ 04 февраля 2012

В итоге я выбрал одинарные кавычки, а не пытался понять, как избежать двойных кавычек:

COMMAND2="ssh -o StrictHostKeyChecking=no -t %s@%s \"su - root -c 'chown root:root /tmp/id_rsa.pub; chmod 600 /tmp/id_rsa.pub; chown root:root /tmp/sshd_config; mkdir /root/.ssh; chown root:root /root/.ssh; chmod 700 /root/.ssh; mv /tmp/id_rsa.pub /root/.ssh/authorized_keys; mv /tmp/sshd_config /etc/ssh/; service sshd reload'\"" % (USER, HOST)
...