技術メモなどに色々バラバラに書いていたssh関係を一度まとめる。 詳細は色々な本などにあるだろうし、過去記事のまとめ程度に抑えておく。
sshは、Secure Shell から名前をとった、リモート端末との通信を行うためのプロトコル、コマンドのことをいう。
sshはRFCにより仕様が規定および公開されている。(20190925時点で調べたもの。今ではもっとあるんだろうけど、面倒だから調べてない)
以下、CEoR改を実装するために必要となりそうなsshの機能のみに限定してのメモ
対象とする実装は、 OpenSSH とする。これは、CEoRで管理をしたい対象がFreeBSD/OpenBSD/Linux系のOS環境であり、これらには標準的にOpenSSHが採用されているからである。
| Option | Config Param name | default | descriptions |
|---|---|---|---|
| -A/-a | 認証Agentの転送を許可/禁止 | ||
| -D | Debug logを引数で指定したファイルに書き出す(-v/-vv/-vvv出力) | ||
| -e | EscapeChar | ~ | 文字/^文字 指定文字/制御文字をエスケープ文字にする |
| none: エスケープ文字を禁止する。(Binary Dataに対して透過になる) | |||
| -F | ~/.ssh/config | 設定ファイルを指定する。 システムdefaultは無視される | |
| -f | sshの認証後、BackGroundに移行する | ||
| -J | 引数で指定されたマシンを踏み台にして対象ホストに接続する | ||
| 対象ホストの名前解決ができなければならない | |||
| -L | LocalForward | Local forward | |
| -l | User | login名 | |
| -N | リモートコマンドを実行しない (-Mと併せて使う) | ||
| -n | stdinを/dev/nullに切り替える。Passphraseなどを入力する必要がある場合 -f を使う |
||
| -O | -Mで作ったMasterへの制御コマンドを送る。 check: Masterがあるかのチェック | ||
| forward: port forwardを要求 / cancel: port forwardをキャンセル | |||
| exit: Master Processを終了する / stop: これ以上の分岐を禁止する | |||
| -o | 設定ファイルと同じ形式でのオプション指定 | ||
| -M | ControlMaster | no | 単一のネットワーク接続において、複数セッションを共有するか |
| -Q | 問い合わせ。cipher(対象暗号の種類)/cipher-auth(認証付き暗号化をサポートする対象暗号の種類) | ||
| mac(メッセージ認証コードの種類)/kex(鍵交換アルゴリズム)/key-cert(証明書の鍵の形式) | |||
| -q | quiet mode | ||
| -R | RemoteForward | リモーロフォワード | |
| -S | ControlPath | Master modeにおける制御用Socketファイルの指定 | |
| -T/-t | RequestTTY | セッションに対してTTYを要求するか? no:要求しない/yes:要求する(-t)/forcce:強制的に割り当て(-tt) | |
| -X/-x | ForwardX11 | no | X11接続を転送するか yes:許可/no:禁止 |
| -y | logをsysぉg経由で飛ばす。defaultではstderrに出力される | ||
| BatchMode | no | Password/Passphrase入力を求めるか? | |
| CheckHostIP | yes | knwnhostsファイルのエントリーとの比較を行うか? | |
| ConnectionAttmpts | 1 | 接続試行回数 | |
| ConnectTimeout | TCP Connectionが成立するまでのTimeout時間の設定 | ||
| ControlPath | Master modeにおける制御用Socketファイルの指定 | ||
| ControlPersist | no: MasterはForegroundのまま、最初のClientが終了した直後に終了 | ||
| yes / 0 : MasterはBackgroundに移行し、永続的に保持される | |||
| 数値(秒) / 時間形式 : idleな時間が指定値を越えると接続が終了 | |||
| OpenSSH 5.6以降でのみ利用可能 | |||
| ForwardAgent | no | 認証エージェントへの接続を転送するか | |
| IdentityFile | 利用する秘密鍵 | ||
| force: 常に要求 /auto: loginセッションの時だけ要求する |
-M もしくは -o ControlMaster=yes を指定し、 ControlPath=[SocketFilename] を指定する。-o ControlMaster=no を指定し、 ControlPath=[SocketFilename] を指定する。-o ControlMaster=autoを指定すると、「Master接続が利用できる場合にはそれを利用、利用できない場合には自動的に新しい接続を作成」する%L : Localのホスト名の最初の部分%l : localのホスト名(hostnameコマンドの返り値)%h : remoteのホスト名%n : コマンドラインで指定された(remote)ホスト名%p : remoteのport番号%r : remoteのログイン名%u : sshを実行したユーザーのログイン名%i : sshを実行したユーザーのUID%C : %l%h%p%rssh -M 127.0.0.1/tmpに置かれるssh -M -S [SocketFileName] 127.0.0.1-Sの引数に記載された[SocketFileName]になるssh -N -f -M -S [SocketFileName] 127.0.0.1-Sの引数に記載された[SocketFileName]になるssh -N -f -O exit -S [SocketFileName] 127.0.0.1[SocketFileName]] に紐づいたssh接続が終了するssh -N -f -M -S [SocketFileName] 127.0.0.1を2回起動するControlMaster=auto 相当の挙動をするshell scriptにおいて、ファイルから1行ずつ読み込んで処理をするような場合、以下のようにかける。
while read line; do echo ${line} done < file
ところが、この手を使ってsshを実行すると、なぜか最初の行しか実行されない
while read line; do ssh xxx.xxx.xxx.xxx ${line} # XXX 期待通りに動かない done < file
原因はsshコマンド実行に伴う標準入力の切替と考えられる。 sshコマンドを実行すると、ローカルホストのstdinからの入力を終了し、sshで指定したリモートホストのstdinからの入力受付を開始する。 従って、ローカルホストのファイルの読込みを終了させた上でsshコマンドを実行し、再びreadコマンドを実行しようとしていると考えられる。もちろん、この時点で既にファイルがcloseされている為、whileが終了してしまう。
対策は、sshに-nオプションをつけること。これよって、sshコマンドのstdin切り替えを禁止することが出来る。
この原因がちっともわからず、数時間を無駄にしてしまった。
while read line; do ssh -n xxx.xxx.xxx.xxx ${line} # これで/dev/nullがsshのstdinにつながる done < file
このほかに、for文で for line in `cat file` で代用する手も考えられるが、これは、行にスペースがある場合、$lineに代入される値が1行まるごとではなく、スペースまでの部分になるので、ここにも明確な罠があると考えられる。これを回避するにはIFSを変えれば良いのだから、
IFS=$'\n' # 区切り文字を" "から"\n"に変える for line in `cat file`; do # while readの代わりにcatで読み込ませる ssh -n xxx.xxx.xxx.xxx ${line} done
あと、whileはちょっと特殊な制御文で、場合によってはwhile内で変数設定しているはずなのにloopをでてくると変数が空のようなことが起こる。 これは、Whileと他のコマンドを組み合わせた場合、組み合わせ方次第で処理がsubshellがわで処理されてしまう事が原因である。 shellでpipelineを用いて実行した処理は、subshellで処理される。while loopの内部でpipelineを利用すると、whileブロック全体がsubshellで処理されるため、whileブロックの内部と外部で変数の共有が出来ない。 このような場合、whileに対して出力をredirectしてやることで解決できる。
while read line; do OUT=`echo ${line} | sed 's/test/test2'` done < $1 echo ${OUT}
なお、/bin/shの引数に -v や -x をつけると、デバッグに大変に役立つ
scpには様々な問題があるということで、scpはDeprecatedになっており、sftpを利用したファイル転送を利用すべきである。
というわけで、メモ
http://d.hatena.ne.jp/cakephper/20120918/1347935609 http://f99aq.hateblo.jp/entry/20090802/1249222491
要するに、/etc/ssh/sshd_configを修正し、対象Dirをroot:wheelにすること。
ちなみに、sshd_configに ForceCommand internal-sftp を追加しないと、passwdに記載されているshellを実行しようとするので注意。
参考
要するに、BSDでは、上記patchを当てないと出来ないが、RSA AuthenticationとChallenge Response Authenticationを組み合わせて二要素認証にするという話。
/etc/ssh/sshd_config の変更点だけ書いておく。
ChallengeResponseAuthentication yes RSAAuthentication yes RequiredAuthentications2 publickey,keyboard-interactive
Password Authenticationを使う事は出来ないっぽいけど、まだ試してない。
ちょっと某所で sshd でのPublickey Authentication時のPublickeyを~/.ssh/authorized_keys以外から持ってくる設定について聞かれたので、ちょっと調べてみた。
AuthorizedKeysCommand に公開鍵を引っ張ってくるscriptを指定したんだけど、認証に失敗するAuthorizedKeysCommand /tmp/pubkey.shAuthorizedKeysCommandUser hogehoge#!/bin/bash -e echo "ssh-rsa AAAA........."
Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
error: Unsafe AuthorizedKeysCommand “/tmp/pubkey.sh”: bad ownership or modes for file /tmp/pubkey.sh が/var/log/auth.logに出力されていた/usr/local/bin/pubkey.shに設置AuthorizedKeysCommand /usr/local/bin/pubkey.sh としてsshd_configに設定chmod 750 /usr/local/bin/pubkey.sh を実行chown root:nobody /usr/local/bin/pubkey.sh を実行
OS-Xでman ssh-addしていたら、-KなるOptionを発見した。
そういえば、むかーしむかしに見たような気もする。
<node> -K When adding identities, each passphrase will also be stored in your
keychain. When removing identities with -d, each passphrase will
be removed from your keychain.
</note>
つまり、ssh-add -K しておけば、その後はいちいちパスフレーズを入力しなくてもよくなる。
MacOS-Xでリモートアクセスを許可すると、sshで接続できるようになる。
しかし、/etc/sshd_configをいじってもsshの待ち受けポートが変わらないので調べてみたら、/System/Library/LaunchDaemons/ssh.plistを修正する必要があるということで、以下のように修正
<key>Sockets</key>
<dict>
<key>Listeners</key>
<dict>
<key>SockServiceName</key>
<string>65535</string>
<key>Bonjour</key>
<array>
<string>ssh</string>
<string>sftp-ssh</string>
</array>
</dict>
</dict>
このSockServiceNameの文字列sshを待ち受けたいport番号にかえればOK。なお、この例では65535にしているが、ポート番号は適当にどうぞ。
なお、当然、この変更を行った後で
% sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist % sudo launchctl load /System/Library/LaunchDaemons/ssh.plist
を実行する事。そうしないと、変更が反映されないよ。ま、再起動でもいいけどね。
Backupを取得するに際して、Backupを元々のServerに置いておいたら、Disk破損の時に一気に死ぬ。 で、そんな事態は救われないので、BackupをRemoteに置いておくために、Backup Scriptまで作ったわけだが、Serverの内側でcronなどでBackupを取得するのは設定ミスとか管理の分散とかが起こってうれしくない。 というわけで、remoteからsshを利用してBackupを取得するようにscriptを作ったのだが、
Pseudo-terminal will not be allocated because stdin is not a terminal.
などといいうErrorが出た。で、これはptyの割り付けないremoteからのコマンドは実行できないということでsshが吐き出すErrorである。
しかし、shell scriptには-tは記載されていて、ちゃんと動くはずだとどはまりをしたわけで…
で、困りに困って調べてみたら、出てました。man ssh
-t Force pseudo-tty allocation. This can be used to execute arbitrary screen-based pro-
grams on a remote machine, which can be very useful, e.g. when implementing menu ser-
vices. Multiple -t options force tty allocation, even if ssh has no local tty.
よく見たら、Multiple -t options force tty allocation, even if ssh has no local tty.だそうな。
要するに、-t -tとしろと。
わかりにくいからメモにしておく。
教訓は、RTFM … orz.
うちの環境にはいまだに古いAlaxalAのL2 SwitchやApresiaのL3 Switchがあるのだが、これが古いssh protocolをしゃべる。 そのため、2023/05時点のmacOS(Ventura/13.3)だとsshで接続しようとした時にsshの暗号化パラメータ(鍵交換や暗号アルゴリズム)が対応していなくて接続できなくなる。
その解消のためには、~/.ssh/configに以下のような設定を入れておくこと。
# for AlaxalA AX2430S
Host [IP Address] [alias name] ...
HostKeyAlgorithms ssh-dss
KexAlgorithms +diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1
# for Apressia
Host [IP Address] [alias name] ...
KexAlgorithms +diffie-hellman-group-exchange-sha1,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1