転載・引用について

ユーザ用ツール

サイト用ツール


tech:ssh

差分

このページの2つのバージョン間の差分を表示します。


tech:ssh [2023/05/13 15:15] (現在) – 作成 - 外部編集 127.0.0.1
行 1: 行 1:
 +====== sshに関して ======
 +技術メモなどに色々バラバラに書いていたssh関係を一度まとめる。
 +詳細は色々な本などにあるだろうし、過去記事のまとめ程度に抑えておく。
  
 +===== ssh とは =====
 +sshは、Secure Shell から名前をとった、リモート端末との通信を行うためのプロトコル、コマンドのことをいう。
 +  * 大本に、rsh(remote shell)がある。rshは、Remote Shellから名前をとったもの
 +    * 他に、telnetやrloginなどもある。何れにしても暗号化などの保護はない。なお、telnetにSSL/TLSを組み合わせたtelnetsもあるが、ほぼ利用されていない。
 +  * rshには、通信保護の機構はなく、通信内容はRPCを利用し、生データが流れていた
 +  * sshでは、RPCを利用することをやめ、ssh daemonとssh client間で暗号化された通信路を用いてデータをやりとりする
 +
 +sshはRFCにより仕様が規定および公開されている。(20190925時点で調べたもの。今ではもっとあるんだろうけど、面倒だから調べてない)
 +  * [[ https://tools.ietf.org/html/rfc4250 | RFC 4250 ]] : The Secure Shell (SSH) Protocol Assigned Numbers
 +  * [[ https://tools.ietf.org/html/rfc4251 | RFC 4251 ]] : The Secure Shell (SSH) Protocol Architecture
 +  * [[ https://tools.ietf.org/html/rfc4252 | RFC 4252 ]] : The Secure Shell (SSH) Authentication Protocol
 +  * [[ https://tools.ietf.org/html/rfc4253 | RFC 4253 ]] : The Secure Shell (SSH) Transport Layer Protocol
 +  * [[ https://tools.ietf.org/html/rfc4254 | RFC 4254 ]] : The Secure Shell (SSH) Connection Protocol
 +  * [[ https://tools.ietf.org/html/rfc4255 | RFC 4255 ]] : Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints
 +  * [[ https://tools.ietf.org/html/rfc4256 | RFC 4256 ]] : Generic Message Exchange Authentication for the Secure Shell Protocol (SSH)
 +
 +===== 機能関係 =====
 +以下、[[https://github.com/sheo0147/CEoR|CEoR]]改を実装するために必要となりそうなsshの機能のみに限定してのメモ
 +
 +対象とする実装は、[[ https://www.openssh.com | 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(証明書の鍵の形式) |
 +| :::    | :::               | :::     | key-plain(証明書ではない鍵の形式)/protocol-version(sshプロトコル番号)
 +| -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セッションの時だけ要求する |
 +
 +==== ControlMaster ====
 +  * Masterになる場合、 ''-M'' もしくは ''-o ControlMaster=yes'' を指定し、 ''ControlPath=[SocketFilename]'' を指定する。
 +  * Masterの接続を流用する場合、''-o ControlMaster=no'' を指定し、 ''ControlPath=[SocketFilename]'' を指定する。
 +    * ControlPathに指定されたSocket Fileがない場合には、通常の接続が行われる
 +  * ''-o ControlMaster=auto''を指定すると、「Master接続が利用できる場合にはそれを利用、利用できない場合には自動的に新しい接続を作成」する
 +  * ControlPathの引数にはEscape Sequenceが利用できる
 +    * ''%L'' : Localのホスト名の最初の部分
 +    * ''%l'' : localのホスト名(hostnameコマンドの返り値)
 +    * ''%h'' : remoteのホスト名
 +    * ''%n'' : コマンドラインで指定された(remote)ホスト名
 +    * ''%p'' : remoteのport番号
 +    * ''%r'' : remoteのログイン名
 +    * ''%u'' : sshを実行したユーザーのログイン名
 +    * ''%i'' : sshを実行したユーザーのUID
 +    * ''%C'' : ''%l%h%p%r''
 +==== ControlMasterに関するCommand line ====
 +  * ''ssh -M 127.0.0.1''
 +    * Masterとして動作し、RemoteのTTYを掴む。
 +    * 制御用socketは(FreeBSDの場合)''/tmp''に置かれる
 +    * 制御用socketのファイル名を取得する方法がない
 +  * ''ssh -M -S [SocketFileName] 127.0.0.1''
 +    * Masterとして動作し、RemoteのTTYを掴む。
 +    * 制御用socketは''-S''の引数に記載された''[SocketFileName]''になる
 +  * ''ssh -N -f -M -S [SocketFileName] 127.0.0.1''
 +    * Masterとして動作し、Socketを作成した後sshはBackgroundに
 +    * 制御用socketは''-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とssh ====
 +shell scriptにおいて、ファイルから1行ずつ読み込んで処理をするような場合、以下のようにかける。
 +
 +<code bash>
 +while read line; do
 +  echo ${line}
 +done < file
 +</code>
 +
 +ところが、この手を使ってsshを実行すると、なぜか最初の行しか実行されない
 +
 +<code bash>
 +while read line; do
 +  ssh xxx.xxx.xxx.xxx ${line} # XXX 期待通りに動かない
 +done < file
 +</code>
 +
 +原因はsshコマンド実行に伴う標準入力の切替と考えられる。
 +sshコマンドを実行すると、ローカルホストのstdinからの入力を終了し、sshで指定したリモートホストのstdinからの入力受付を開始する。
 +従って、ローカルホストのファイルの読込みを終了させた上でsshコマンドを実行し、再びreadコマンドを実行しようとしていると考えられる。もちろん、この時点で既にファイルがcloseされている為、whileが終了してしまう。
 +
 +対策は、sshに''-n''オプションをつけること。これよって、sshコマンドのstdin切り替えを禁止することが出来る。
 +
 +この原因がちっともわからず、数時間を無駄にしてしまった。
 +
 +<code bash>
 +while read line; do
 +  ssh -n xxx.xxx.xxx.xxx ${line} # これで/dev/nullがsshのstdinにつながる
 +done < file
 +</code>
 +
 +このほかに、for文で ''for line in `cat file`'' で代用する手も考えられるが、これは、行にスペースがある場合、$lineに代入される値が1行まるごとではなく、スペースまでの部分になるので、ここにも明確な罠があると考えられる。これを回避するにはIFSを変えれば良いのだから、
 +
 +<code bash>
 +IFS=$'\n' # 区切り文字を" "から"\n"に変える
 +for line in `cat file`; do # while readの代わりにcatで読み込ませる
 +  ssh -n xxx.xxx.xxx.xxx ${line}
 +done
 +</code>
 +
 +あと、whileはちょっと特殊な制御文で、場合によってはwhile内で変数設定しているはずなのにloopをでてくると変数が空のようなことが起こる。
 +これは、Whileと他のコマンドを組み合わせた場合、組み合わせ方次第で処理がsubshellがわで処理されてしまう事が原因である。
 +shellでpipelineを用いて実行した処理は、subshellで処理される。while loopの内部でpipelineを利用すると、whileブロック全体がsubshellで処理されるため、whileブロックの内部と外部で変数の共有が出来ない。
 +このような場合、whileに対して出力をredirectしてやることで解決できる。
 +
 +<code bash>
 +while read line; do
 +  OUT=`echo ${line} | sed 's/test/test2'`
 +done < $1
 +echo ${OUT}
 +</code>
 +
 +なお、/bin/shの引数に ''-v'' や ''-x'' をつけると、デバッグに大変に役立つ
 +
 +===== sftpとscp関連 =====
 +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を実行しようとするので注意。
 +
 +===== sshと二要素認証 =====
 +参考
 +  * http://konishi.me/?p=175
 +  * http://jerrywalsh.org/2008/two-factor-authentication-with-openssh-on-freebsd-7-0-1113.html
 +
 +要するに、BSDでは、上記patchを当てないと出来ないが、RSA AuthenticationとChallenge Response Authenticationを組み合わせて二要素認証にするという話。
 +
 +/etc/ssh/sshd_config の変更点だけ書いておく。
 +
 +<code>
 +ChallengeResponseAuthentication yes
 +RSAAuthentication yes
 +
 +RequiredAuthentications2 publickey,keyboard-interactive
 +</code>
 +
 +Password Authenticationを使う事は出来ないっぽいけど、まだ試してない。
 +
 +===== sshdでPublickeyをauthorized_keys以外から持ってくる =====
 +
 +ちょっと某所で sshd でのPublickey Authentication時のPublickeyを~/.ssh/authorized_keys以外から持ってくる設定について聞かれたので、ちょっと調べてみた。
 +
 +==== 問題 ====
 +  * ''AuthorizedKeysCommand'' に公開鍵を引っ張ってくるscriptを指定したんだけど、認証に失敗する
 +  * sshd_configに以下の記述
 +    * ''AuthorizedKeysCommand /tmp/pubkey.sh''
 +    * ''AuthorizedKeysCommandUser hogehoge''
 +  * pubkey.shは以下の通り
 +    * <code - pubkey.sh>
 +#!/bin/bash -e
 +echo "ssh-rsa AAAA........."
 +</code>
 +  * ssh -v の結果
 +    * <code>
 +Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
 +</code>
 +
 +==== 解決 ====
 +  * sshdのlogを見ると、''error: Unsafe AuthorizedKeysCommand "/tmp/pubkey.sh": bad ownership or modes for file /tmp/pubkey.sh'' が''/var/log/auth.log''に出力されていた
 +  * 色々調べてみると、以下が判明
 +    * sshdは以下の条件のうち一つでも満たすと、上記エラーを吐く
 +      - 他人に書き換えられる可能性のあるDirectoryに設置されている(/tmpとかはやばい)
 +      - Ownerがrootではない
 +      - Owner以外が書き換えることができる(g+wとかo+wだとまずい)
 +      - AuthorizedKeysCommandUser に指定されたUser Accountで実行できない
 +  * というわけで、以下のように修正
 +    * Scriptを''/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'' を実行
 +    * sshdを再起動
 +
 +==== 結論 ====
 +  * この手法を使えば、LDAPでsshの公開鍵を引っ張ってくることができそうだ
 +  * OpenSSHはSecurity的に相当細かくCheckしているので、ある程度はこの手法を利用しても安全性を確保できそうだ
 +  * 意外と問題の原因が分かりにくいので、追いかけるのが大変
 +  * 俺はエスパーじゃないので、何をどうしたいのか説明してくれ
 +
 +===== sshの秘密鍵をOS-XのKeychain Accessに登録 =====
 +
 +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'' しておけば、その後はいちいちパスフレーズを入力しなくてもよくなる。
 +
 +===== OS-Xでsshdの待ち受けポートを変更する =====
 +
 +MacOS-Xでリモートアクセスを許可すると、sshで接続できるようになる。
 +
 +しかし、/etc/sshd_configをいじってもsshの待ち受けポートが変わらないので調べてみたら、''/System/Library/LaunchDaemons/ssh.plist''を修正する必要があるということで、以下のように修正
 +
 +<code>
 +       <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>
 +</code>
 +
 +このSockServiceNameの文字列sshを待ち受けたいport番号にかえればOK。なお、この例では65535にしているが、ポート番号は適当にどうぞ。
 +
 +なお、当然、この変更を行った後で
 +<code>
 +% sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
 +% sudo launchctl load /System/Library/LaunchDaemons/ssh.plist
 +</code>
 +を実行する事。そうしないと、変更が反映されないよ。ま、再起動でもいいけどね。
 +
 +===== sshとcron =====
 +
 +Backupを取得するに際して、Backupを元々のServerに置いておいたら、Disk破損の時に一気に死ぬ。
 +で、そんな事態は救われないので、BackupをRemoteに置いておくために、Backup Scriptまで作ったわけだが、Serverの内側でcronなどでBackupを取得するのは設定ミスとか管理の分散とかが起こってうれしくない。
 +というわけで、remoteからsshを利用してBackupを取得するようにscriptを作ったのだが、
 +<code>
 +Pseudo-terminal will not be allocated because stdin is not a terminal.
 +</code>
 +などといいうErrorが出た。で、これはptyの割り付けないremoteからのコマンドは実行できないということでsshが吐き出すErrorである。
 +
 +しかし、shell scriptには''-t''は記載されていて、ちゃんと動くはずだとどはまりをしたわけで...
 +
 +で、困りに困って調べてみたら、出てました。man ssh
 +<code>
 + -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.
 +</code>
 +
 +よく見たら、''Multiple -t options force tty allocation, even if ssh has no local tty.''だそうな。
 +
 +要するに、''-t -t''としろと。
 +
 +わかりにくいからメモにしておく。
 +
 +教訓は、RTFM ... orz.
 +
 +===== 古いNetwork機器に対するssh接続 =====
 +うちの環境にはいまだに古いAlaxalAのL2 SwitchやApresiaのL3 Switchがあるのだが、これが古いssh protocolをしゃべる。
 +そのため、2023/05時点のmacOS(Ventura/13.3)だとsshで接続しようとした時にsshの暗号化パラメータ(鍵交換や暗号アルゴリズム)が対応していなくて接続できなくなる。
 +
 +その解消のためには、~/.ssh/configに以下のような設定を入れておくこと。
 +
 +<code>
 +# 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
 +</code>
tech/ssh.txt · 最終更新: 2023/05/13 15:15 by 127.0.0.1

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki