pexpect 和 ssh:如何在 su - root -c 之后格式化命令字符串 [英] pexpect and ssh: how to format a string of commands after su - root -c

查看:88
本文介绍了pexpect 和 ssh:如何在 su - root -c 之后格式化命令字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试遍历服务器列表 &更改一组服务器上的 sshd 配置的密码,以便我可以使用无密码 SSH 密钥通过 root 登录/运行命令.

I am trying to iterate through a list of servers & passwords to change the sshd configs on a group of servers so that I can login/run commands via root using passwordless SSH keys.

我可以在 bash 中轻松完成此操作,但我正在尝试学习 Python,并且(显然)希望放弃手动输入密码.

I can do this easily in bash but I'm trying to learn Python and (obviously) would like to forego entering in passwords manually.

这是我想做的事情的重点:

Here's the bash of what I want to do:

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\""

我已经接近使用 pexpect 在 Python 中做到这一点了:

I've gotten close to doing this in Python with 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 失败了:

When I run that COMMAND1 (scp'ing) works fine. But COMMAND2 fails:

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 文件,我会得到:

If I remove the /etc/ssh/sshd_config file on the remote server before running the script I get:

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 非常新,所以任何建议都值得赞赏.谢谢.

I'm not even sure how to debug this to see where it's messing up. I don't think it's parsing COMMAND2 properly, though. Pretty new to Python so any advice is appreciated. Thanks.

推荐答案

您在双引号中有 COMMAND2 并正确转义任何嵌入的双引号,但您还需要对任何已经转义的双引号进行双重转义.换句话说,并不是真正的 Python 问题.不过,您可以将最外层的引号切换为 Python 三引号.阅读起来也会更容易.

You have COMMAND2 in double quotes and correctly escape any embedded double quotes, but you also need to double-escape any already-escaped double quotes. In other words, not really a Python problem. You could switch to Python triple quotes for the outermost quotes, though. It would be easier to read, too.

实际上,对引用进行任何适当的消歧都可以.由于 shell 也提供单引号,因此您的单引号解决方案很好.Python 允许您使用单引号或许多其他引用工具,如果您还没有解决问题,我会建议您这样做(因为这样您就可以选择不需要对字符串本身进行任何更改的引号;更少的空间错误).

Actually, any proper disambiguation of the quoting will do. Since the shell offers single quotes as well, your solution with single quotes is fine. Python would allow you to use single quotes or a number of other quoting facilities, which I would recommend if you hadn't already solved the problem (because then you can choose quotes which don't require any changes to the string itself; less room for error).

所以,这些都应该没问题:

So, any of these should be fine:

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)

我需要在三引号中添加一个空格以消除相邻双引号的歧义.但是您可以改用三重单引号.此外,三重引号(单引号或双引号)允许您嵌入换行符,从而显着提高可读性:

I needed to add a space to the triple-quotes in order to disambiguate the adjacent double quote. But you could use triple single quotes instead. Also, triple quotes (single or double) allow you to embed newlines, which improves legibility significantly:

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)

这篇关于pexpect 和 ssh:如何在 su - root -c 之后格式化命令字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆