2

サーバー A からサーバー B にいくつかのファイルをデプロイする必要があります。サーバー A に SSH 経由で接続し、そこから ssh 経由でサーバー B に接続します。サーバー A に保存されている秘密鍵と、サーバー B にある公開鍵を使用します。 authorized_keys ファイル。A から B への接続は、サーバー A にある Bash シェル スクリプト内で行われます。

セキュリティ意識の高い管理者が、サーバー A に保存されている私の SSH 秘密鍵はパスフレーズで保護されていないことを指摘するまで、これはすべて正常に機能し、シンプルでうまく機能します。 B、そして C、D、E、F、G. 彼には一理あると思います。

彼は、パスフレーズを追加し、シェル スクリプトを変更して、呼び出しの先頭に aa 行を追加するという複雑なシナリオを提案しています。

ssh-keygen -p -f {private key file}  

古いパスフレーズのプロンプトにパスフレーズを入力し、新しいパスフレーズの (2 つの) プロンプトにパスフレーズを削除する return だけで応答し、最後に scp コマンドを呼び出した後に応答します。

ssh-keygen -p -f {private key file} 

もう一度、パスフレーズを元に戻します

私は「うん!」と言います。

最初にスクリプト内のパスフレーズ ONCE を次のように読み取ることで、それを少し改善できます。

read -s PASS_PHRASE

次に、ssh-keygen の -N および -P パラメーターを使用して、必要に応じてそれを提供します。

ほとんど使えますが、私はシェル スクリプトのインタラクティブなプロンプトが嫌いです。これを 1 つのインタラクティブなプロンプトにまとめたいのですが、パスフレーズを取り除くために Enter キーを 2 回押さなければならない部分が致命的です

これはコマンドラインから機能します:

ssh-keygen -p -f {private key file} -P {pass phrase} -N ''

シェルスクリプトからではありません。そこでは、-N パラメータを削除し、2 つのリターンを入力する必要があることを受け入れる必要があるようです。

それが私にできる最善のことです。誰でもこれを改善できますか?または、これを処理するより良い方法はありますか? ないなんて信じられない。

パスフレーズを入力することなくこれを安全に処理する方法が最善ですが、それはあまりにも多くのことを求めている可能性があります. スクリプトの呼び出しごとに 1 回で解決します。

これは、スケルトン形式のスクリプト全体の簡略化されたバージョンです

#! /bin/sh
KEYFILE=$HOME/.ssh/id_dsa
PASSPHRASE=''

unset_passphrase() {
        # params
        # oldpassword keyfile
        echo "unset_key_password()"
        cmd="ssh-keygen -p -P $1 -N '' -f $2"
        echo "$cmd"
        $cmd
        echo 
}

reset_passphrase() {
        # params
        # oldpassword keyfile
        echo "reset_key_password()"
        cmd="ssh-keygen -p -N '$1' -f $2" 
        echo "$cmd"
        $cmd
        echo
}

echo "Enter passphrase:"
read -s PASSPHRASE
unset_passphrase $PASSPHRASE $KEYFILE
# do something with ssh
reset_passphrase $PASSPHRASE $KEYFILE
4

4 に答える 4

4

ssh-agent を確認してください。パスフレーズをキャッシュするため、セッション数に関係なく、一定期間キーファイルを使用できます。

ssh-agent の詳細は次のとおりです。

于 2011-06-22T22:17:27.717 に答える
2

OpenSSH は、いわゆる「コントロール マスター」モードをサポートしています。このモードでは、一度接続すると、バックグラウンドで実行したままにし、その後、他の ssh インスタンス (scp、rsync、git などを含む) にその既存の接続を再利用させることができます。これにより、(コントロール マスターのセットアップ時に) パスワードを 1 回入力するだけで、同じ宛先に対して複数の ssh コマンドを実行できます。

詳しくは で検索しControlMasterman ssh_configください。

上の利点ssh-agent:

  • 実行することを覚える必要はありませんssh-agent
  • ssh の公開鍵と秘密鍵のペアを生成する必要はありません。これは、スクリプトが多くのユーザーによって実行される場合に重要です (ほとんどの人は ssh キーを理解していないため、大勢の人にそれらを生成させるのは面倒です)エクササイズ)
  • 構成ssh-agent方法によっては、スクリプトの途中でキーがタイムアウトになる場合があります。これはしません
  • 開始される TCP セッションは 1 つだけなので、何度も何度も接続している場合 (たとえば、多数の小さなファイルを一度に 1 つずつコピーする場合) は、はるかに高速です。

使用例 (スタック オーバーフローの壊れた構文の強調表示を許してください):

REMOTE_HOST=server

log() { printf '%s\n' "$*"; }
error() { log "ERROR: $*" >&2; }
fatal() { error "$*"; exit 1; }
try() { "$@" || fatal "'$@' failed"; }

controlmaster_start() {
    CONTROLPATH=/tmp/$(basename "$0").$$.%l_%h_%p_%r
    # same as CONTROLPATH but with special characters (quotes,
    # spaces) escaped in a way that rsync understands
    CONTROLPATH_E=$(
        printf '%s\n' "${CONTROLPATH}" |
        sed -e 's/'\''/"'\''"/g' -e 's/"/'\''"'\''/g' -e 's/ /" "/g'
    )
    log "Starting ssh control master..."
    ssh -f -M -N -S "${CONTROLPATH}" "${REMOTE_HOST}" \
        || fatal "couldn't start ssh control master"
    # automatically close the control master at exit, even if
    # killed or interrupted with ctrl-c
    trap 'controlmaster_stop' 0
    trap 'exit 1' HUP INT QUIT TERM
}

controlmaster_stop() {
    log "Closing ssh control master..."
    ssh -O exit -S "${CONTROLPATH}" "${REMOTE_HOST}" >/dev/null \
        || fatal "couldn't close ssh control master"
}

controlmaster_start
try ssh -S "${CONTROLPATH}" "${REMOTE_HOST}" some_command
try scp -o ControlPath="${CONTROLPATH}" \
    some_file "${REMOTE_HOST}":some_path
try rsync -e "ssh -S ${CONTROLPATH_E}" -avz \
    some_dir "${REMOTE_HOST}":some_path

# the control master will automatically close once the script exits
于 2011-06-23T00:40:15.097 に答える
1

これに対する別の解決策を指摘できます。キーをサーバーに保存する代わりにA、キーをローカルに保持します。Bここで、ポート上のサーバーへのローカル ポート転送を作成します4000

ssh -L 4000:B:22 usernam@A

次に、新しいターミナルで、トンネルを介してサーバーに接続しますB

ssh -p 4000 -i key_copied_from_a user_on_b@localhost

ただし、これがあなたにとってどれほど実現可能かはわかりません。

于 2011-06-22T22:17:08.060 に答える
0

あなたが発見したように、コマンドを文字列として構築するのは難しいです。配列を使用する方がはるかに堅牢です。

cmd=( ssh-keygen -p -P "$1" -N "" -f "$2" )
echo "${cmd[@]}"
"${cmd[@]}"

または、位置パラメーターを使用することもできます

passphrase="$1"
keyfile="$2"
set -- ssh-keygen -p -P "$passphrase" -N "" -f "$keyfile"
echo "$@"
"$@"

空の引数は引用符で囲まれてエコーされませんが、そこにあります

于 2011-06-23T02:21:05.400 に答える