SSHを通してリモートサーバ接続&自動処理を実行する



単純な作業はできるだけプログラムで自動化するコードを書きたいことがあります。

次のような処理を自動的に行いたい場合の方法を幾つか紹介します。

スポンサードリンク

expect を利用してみる

Expectスクリプトは、複数のCLIコマンドをバッチ・モードで自動化するために使用できます。

存在していない場合にはインストール

# sudo apt-get install expect

他の命令と併せて使う場合

#!/bin/bash

expect -c "
set timeout -1
spawn source ./build/download_jp.sh
expect \"GID\"
send \"$U\r\"
#expect \"パスワード\"
send \"$PW\r\"
expect \"$ \"
interact
"

set timeout

設定した秒数の間、標準入力から応答がないとexpectは、終了します。上記例だと、5秒でタイムアウトする設定になります。「-1」を設定すると、タイムアウトしない設定になります。

spawn

自動で実行したいコマンドを指定します。上記の場合、「ssh www.hoge.co.jp」を実行します。

expect

指定された文字列(「”」に囲まれた文字)と標準入力のデータとを正規表現で比較し、一致するまで以降の命令を実行しません。例だと、「Enter passphrase for key」が、画面に表示されるのを待つことになります。

send

指定された文字列(「”」に囲まれた文字)を先に実行したコマンドのジョブに送信します。つまり、「hogehoge38\n」とパスフレーズを入力したことになります。文字列最後の「\n」は、改行(Enterを押下)を意味します。

interact

実行ジョブの標準入出力をキーボードと画面にします。これで、自動実行を終了し、端末からsshでログインしたのと同じ状態になります。

#!/bin/bash

expect -c "
set timeout 600
spawn /usr/bin/adb shell
expect \"root@\"
send \"dtdebug -e 1\r\"
expect \"Please input number\"
send \"2\r\"
expect \"Please input number\"
send \"1\r\"
expect \"Please input number\"
send \"1\r\"
interact
"

SSHPass コマンドで実現する

パスワードが格納されているファイルに対して、より安全なアクセス許可が必要な方法です。

まずはインストールしましょう

sudo apt-get -y install sshpass

使用例

# パスワードを指定
sshpass -p 'password' ssh -o StrictHostKeyChecking=no user@host 'command'
sshpass -p 'password' scp -o StrictHostKeyChecking=no localfile user@host:/path/to/copy

# パスワードの記載されているファイルを指定
sshpass -f passwordFile ssh -o StrictHostKeyChecking=no user@host 'command'
sshpass -f passwordFile scp -o StrictHostKeyChecking=no localfile user@host:/path/to/copy

「-o StrictHostKeyChecking=no」 を指定しない場合は、初回接続時に接続先ホストの確認メッセージがでるため失敗する場合があります。

シェルで自動化する

環境変数 SSH_ASKPASSに、パスワードを返すシェルスクリプトを設定することで実現しています。

公開鍵認証方式が使えない(サーバ側もクライアント側も変更できない)場合に便利です。

#!/bin/bash

# 接続先情報
SSH_USER=test
SSH_PASS=mypass
SSH_HOST=your_ssh_server
REMOTE_CMD="ls -al"


# 後述のSSH_ASKPASSで設定したプログラム(本ファイル自身)が返す内容
if [ -n "$PASSWORD" ]; then
  cat <<< "$PASSWORD"
  exit 0
fi

# SSH_ASKPASSで呼ばれるシェルにパスワードを渡すために変数を設定
export PASSWORD=$SSH_PASS

# SSH_ASKPASSに本ファイルを設定
export SSH_ASKPASS=$0
# ダミーを設定
export DISPLAY=dummy:0

# SSH接続 & リモートコマンド実行
exec setsid ssh $SSH_USER@$SSH_HOST $REMOTE_CMD

SSHで接続してls -alを実行するだけの例です。

Pythonで実現する

Pythonからssh接続を行うためには paramiko というライブラリをインストールする必要があります。

また、SOCKSプロキシ経由でリモートサーバへ接続を行う必要がある環境の方は、Pysocksというライブラリが利用可能です。

pip install paramiko
pip install PySocks

スクリプトは次のようになります。

# coding: utf8
# SSH&SOCKSプロキシを通してリモートサーバ接続を実行

import paramiko
import socks
import socket

# 修正箇所 ==================================
USERNAME   = ""
PASSWORD   = ""
IP_ADDRESS = ""
PORT       = 22
PROXY_HOST = ""
PROXY_PORT = 1080
COMMAND    = "ls -a"
# ここまで ==================================

if (PROXY_HOST != ""):
    # Proxyサーバの情報を引数として、socks.socksocketオブジェクトを生成
    socks.set_default_proxy(socks.SOCKS5, PROXY_HOST, int(PROXY_PORT))
    # socketオブジェクトを2で生成したsocks.socksocketで上書き
    socket.socket = socks.socksocket

with paramiko.SSHClient() as ssh:
    # 「Are you sure you want to continue connecting (yes/no) 」と表示されても接続
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
 
    # ssh接続
    ssh.connect(IP_ADDRESS, port=int(PORT), username=USERNAME, password=PASSWORD, timeout=30)
 
    # コマンド実行
    stdin, stdout, stderr = ssh.exec_command(COMMAND)
 
    # コマンド実行後に標準入力が必要な場合
    # stdin.write('password\n')
    # stdin.flush()
 
    # 実行結果を表示
    for o in stdout:
        print('[std]', o, end='')
    for e in stderr:
        print('[err]', e, end='')

プログラミングができる方は、こちらの方法が自由度が高いかもしれません。

スポンサードリンク