Skip to content
Update ssh authored by umaumax's avatar umaumax
[[_TOC_]]
## 設定ファイル
### `~/.ssh/config`
#### ProxyJump
[多段SSHならProxyJump!さよならProxyCommand | にっしーラボ]( https://nissy-lab.com/blogs/multiple-ssh-proxyjump/ )
#### sshの接続先の名称で処理を振り分けたい
[SSHのDynamic Forwardを気軽に使うTIPS \| Zenn]( https://zenn.dev/hnw/articles/36e70c0980c8786c7154 )
#### [sshをproxy経由でつなぐ \- @znz blog]( https://blog.n-z.jp/blog/2018-08-12-ssh-over-proxy.html )
``` bash
sudo apt-get install -y connect-proxy
```
``` conf
Host github github.com
HostName github.com
User git
IdentityFile ~/.ssh/XXX_id_rsa
ProxyCommand connect -H proxy-XXX.com:10080 %h %p
```
#### sshのpublic key
`~/.ssh/config``IdentityFile`のファイル名+`.pub`のファイルの形式が不正の場合
```
key_load_public: invalid format
```
というメッセージが表示される
ファイル形式が、一見、正しくとも、`~/.ssh/authorized_keys`のように複数のpublic keyが登録されている場合(他のサーバの`authorized_keys`を流用している場合)に、
なぜか秘密鍵を利用したsshアクセスができなくなっている
おそらく、サーバからではなく、localのpublic keyの先頭行と比較して弾いている?
### `~/.ssh/known_hosts`
defaultでhash化されているので、下記を`~/.ssh/config`へ適用するとhash化されなくなる
```
Host *
HashKnownHosts no
```
* [SSHのホスト鍵設定 \- 簡潔なQ]( https://qnighy.hatenablog.com/entry/2017/10/29/220000 )
* [github の IP アドレスをまとめて known\_hosts に登録する — KaoriYa]( https://www.kaoriya.net/blog/2016/07/04/ )
* hash化しないようにすれば,上記のページの通り,`github.com`のすべてのIPアドレスを一括で登録できるようになる
### sshd(/etc/ssh/sshd_config)
#### デフォルト値
`man sshd_config` [sshd\_config\(5\)]( https://www.freebsd.org/cgi/man.cgi?sshd_config(5) )
#### 設定ファイルの文法チェック
``` bash
sshd -t
```
## rootユーザへパスワード入力無しでログイン(鍵不使用)
[linux \- How do I completely remove root password \- Stack Overflow]( https://stackoverflow.com/questions/11700690/how-do-i-completely-remove-root-password )
1. rootのパスワードをなしにする
`passwd -d root`
具体的には`/etc/shadow``root`の行の2番目の項目が空白になっていればOK
`sed -i 's/^root:[^:]\+:/root::/' /etc/shadow`
2. sshdの設定でパスワードなしログインを許可する
`/etc/ssh/cat sshd_config`
```
PasswordAuthentication yes # default: yes
PermitRootLogin yes # default: yes
PermitEmptyPasswords yes # default: no
UsePAM no # default: no
```
各デフォルト設定: [sshd\_config\(5\)]( https://www.freebsd.org/cgi/man.cgi?sshd_config(5) )
`sudo service sshd restart`で再起動する
## ssh中にhang upした場合の対処法
* [SSH Escape Sequences \- Today I Learned]( https://til.hashrocket.com/posts/d909a57428-ssh-escape-sequences )
* [How can I break out of ssh when it locks? \- Ask Ubuntu]( https://askubuntu.com/questions/29942/how-can-i-break-out-of-ssh-when-it-locks )
* [networking \- Why do consoles sometimes hang forever when SSH connection breaks? \- Server Fault]( https://serverfault.com/questions/283129/why-do-consoles-sometimes-hang-forever-when-ssh-connection-breaks )
> There is a "secret" keyboard shortcut to force an exit :~) From the frozen session, hit these keys in order: Enter~. The tilde (only after a newline) is recognized as an escape sequence by the ssh client, and the period tells the client to terminate it's business without further ado.
例えば,2重でsshをしているときには,`<Enter>`, `~`, `~`, `.`を入力すればよい
(`~`の個数番目の`ssh`がcloseされる)
### [Debian/shutdownやrebootするとssh接続の端末がハングする \- Linuxと過ごす]( https://linux.just4fun.biz/?Debian/shutdown%E3%82%84reboot%E3%81%99%E3%82%8B%E3%81%A8ssh%E6%8E%A5%E7%B6%9A%E3%81%AE%E7%AB%AF%E6%9C%AB%E3%81%8C%E3%83%8F%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B )
サーバ側の設定でこの現象を防止することができるらしい
## ポートフォワーディング
[sshポートフォワーディング \- Qiita]( https://qiita.com/mechamogera/items/b1bb9130273deb9426f5 )
`-f`を指定するとbackgroundになり、わかりにくいので、単に、`-N`だけがおすすめ
フォワードする方向は片方向のみであることに注意
### リモートフォワード(リモートからローカルの方向へつなぐ)
`[local] -> [target] <-> [target2]` (矢印の方向にアクセス可能な環境を仮定)
`ssh -N $TARGET -R 8080:localhost:10080`
としたとき
`$TARGET:8080`->`localhost:10080`の方向つながるが、`$TARGET`外から`$TARGET:8080`へのアクセスはできない
`$TARGET`外からアクセスしたい場合は下記の3通り
* A. $TARGET上で`ssh -N $TARGET2 -R 9090:localhost:8080`としてコネクションを追加で貼る必要がある
* `$TARGET2:9090` -> `$TARGET:8080` -> `localhost:10080`となる
* B. `/etc/ssh/sshd_config``GatewayPorts yes`を追加する(`GatewayPorts`のデフォルト値は`no`)
* C. 単に`$TARGET`を経由させずに直接`ssh -N $TARGET2 -R 9090:localhost:10080`
FROM_HOST -> HOST -> TO_HOSTの3wayのようなつなぎ方も可能
``` bash
ssh -N $FROM_HOST -R $FROM_PORT:$TO_HOST:$TO_PORT
```
このとき、両方ともHOSTからsshできればOK(FROM_HOSTからTO_HOSTへssh接続するわけではない)
### ローカルフォワード(ローカルからリモートの方向へつなぐ)
ローカルフォワードのときは下記のオプションを付加すると簡単に指定できる
> -g Allows remote hosts to connect to local forwarded ports. If used on a multiplexed connection, then this option must be specified on the master process.
`ssh -g -L 8080:$TARGET2:10080 $TARGET`
`localhost:8080` -> `$TARGET` -> `$TARGET2:10080`とつながる
> * -f: Requests ssh to go to background just before command execution.
> * -N: Do not execute a remote command. This is useful for just forwarding ports.
`-g`なし
``` bash
$ ss -atn
LISTEN 0 128 ::1:8081 :::*
LISTEN 0 128 127.0.0.1:8081 *:*
```
`-g`あり
``` bash
$ ss -atn
LISTEN 0 128 *:8081 *:*
LISTEN 0 128 :::8081 :::*
```
### 簡単にポートフォワーディングしてアクセスしたい
よく利用するリモートターゲットの`~/.ssh/config`の接続先に下記のようにまとめて記述しておくと`localhost:xxx`としてアクセスできるので便利(多重に接続してもエラーなし)
```
LocalForward 10000 localhost:10000
LocalForward 10001 localhost:10001
LocalForward 10002 localhost:10002
LocalForward 10003 localhost:10003
LocalForward 10004 localhost:10004
LocalForward 10005 localhost:10005
LocalForward 10006 localhost:10006
LocalForward 10007 localhost:10007
LocalForward 10008 localhost:10008
LocalForward 10009 localhost:10009
```
特に複数のリモートターゲットがある場合には便利
同様のことを実現したい場合にはvscodeのremote sshでリモートターゲットに接続していれば上記相当の処理が自動的に行われる
### firewall機能によって、ローカルIPアドレスでのアクセスが禁止されているときの抜け穴の構築方法(ssh portfowarding利用)
```
# $FIREWALL_MACHINE: firewall機能で制限されているマシンで実行
ssh -N -R $PROXY_MACHINE 10080:localhost:80
# $PROXY_MACHINE: proxyとして利用する適当なマシンで実行する(これは上のremote portforwardingのポート(10080)が基本的にこのプロキシマシンのローカルに制限されるので、それを公開するためのコマンド)
ssh -N -g -L 8080:localhost:10080 localhost
```
`$PROXY_MACHINE:8080` => `$PROXY_MACHINE:10080` => `$FIREWALL_MACHINE:80`の方向でネットワークアクセスができる(これでwebsocketのport forwardingができることを確認済み)
## `~/.ssh/config`なしの多段ProxyCommand利用時の注意
[ssh\_config\(5\) \- Linux manual page]( https://man7.org/linux/man-pages/man5/ssh_config.5.html#TOKENS )
`%h`/`%p`などは多段化するときにはエスケープする必要がある(e.g. `%h:%p`, `%%h:%%p`, `%%%%h:%%%%p`)
``` bash
ssh -oProxyCommand='ssh -W %h:%p -oProxyCommand="ssh -W %%h:%%p -oProxyCommand=\"ssh -W %%%%h:%%%%p HOST_A\" HOST_B" HOST_C' HOST_D hostname
```
正しいケース
HOST_A -%%h:%%p-> HOST_B -%h:%p-> HOST_C
の順番で接続する
``` bash
ssh -oProxyCommand='ssh -W %h:%p -oProxyCommand="ssh -W %%h:%%p HOST_A" HOST_B' HOST_C hostname
```
誤ったケース
HOST_A -%h:%p-> HOST_Bで意図せずに接続されてしまうので、
HOST_A -%h:%p-> HOST_Cとなる
``` bash
ssh -oProxyCommand='ssh -W %h:%p -oProxyCommand="ssh -W %h:%p HOST_A" HOST_B' HOST_C hostname
```
## ダイナミックポートフォワード
ssh接続先をsocks proxyサーバとして利用する機能で,firefoxのプロキシ設定をsocksとすることで利用できる(curlならば`--socks5`オプションを利用する)
[ssh DynamicForwardでセキュアなssh接続 \- 自分用メモ]( https://hoshi-sbg.hatenablog.com/entry/2020/03/18/180234 )
## Xをサポートしていない環境でクリップボードのコピーを行う
[Forward your clipboard via SSH reverse tunnels]( https://gist.github.com/dergachev/8259104 )
下記を`~/.ssh/config`に加える(単なる`Host *`では、例えば、git接続時にも適用されてしまうことに注意)
```
Host hoge*
RemoteForward 5556 localhost:5556
```
下記のクリップボードサーバを動かす
``` bash
while true; do nc -l 5556 | xclip -sel clip; done
# start clipboard daemon
if ! pgrep -f clipboard-daemon >/dev/null; then
nohup bash -c "exec -a clipboard-daemon bash -c 'while true; do { nc -d -l 5556 || sleep 1; } | xclip -sel clip; done'" >/dev/null 2>&1 &
fi
```
ssh先のサーバにて
``` bash
function c() {
# way 1
# cat | nc -q0 localhost 5556
# way 2
# cat | telnet localhost 5556
# way 3
# bash -c 'cat > /dev/tcp/127.0.0.1/5556'
# way 4
python3 <(
cat <<EOF
#!/usr/bin/env python3
import socket
import sys
import argparse
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('host', type=str)
parser.add_argument('port', type=int)
args, extra_args = parser.parse_known_args()
data = sys.stdin.buffer.read()
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((args.host, args.port))
n = client.send(data)
if n != len(data):
print("failed to send data (data len = {}, send data len = {})".format(len(data), n), file=sys.stderr)
client.close()
if __name__ == '__main__':
main()
EOF
) localhost 5556
}
```
## ssh先でterminal経由でファイルをコピー&ペーストしたい
* clipboardを利用する方法
* e.g. base64
* 長すぎると,terminalの挙動がとてつもなく重くなる(zshのpluginの影響であり,bashなら問題ない)
* 短い文字量ならば問題ない
* tarコマンドを利用することで、実行権限付きでファイルをコピーでき、ディレクトリも対象にできる
* ネットワークを利用する方法(一時的なサーバを利用)
* ただし、サーバによっては自由にネットワークへ接続できないことに注意
dotfilesに`pack`コマンドを作成した
## ssh rsa非推奨
[SSH 公開鍵を ssh-rsa から強い暗号に書き換える - Qiita]( https://qiita.com/katzueno/items/4319fffc8b0b0b50d8a6 )
e.g. `ssh-keygen -t ecdsa -b 521`
## tips
### [while内でsshを使うと1回で止まる \- Miuran Business Systems]( http://site.m-bsys.com/error/whileread-ssh )
use `ssh -n` for avoid staling `stdin` (`-n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background.`)
### [sshの鍵を作るときにちょっとだけ気にしたいこと \| Developers\.IO]( https://dev.classmethod.jp/articles/ssh-keygen-tips/ )
`-C ""`を追記することで,hostnameが共通鍵にコメントとしてはいることを防止できる
### ssh上でreboot
rebootの処理自体はsshが親プロセスでどうさするのではないため、セッションが切れても問題ないと考えられる
## トラブルシューティング
### 意図していない秘密鍵が利用される
`IdentitiesOnly` `yes`: IdentityFile で指定した秘密鍵でのみ認証を試みる設定を`~/.ssh/config`へ追加すると良い
デフォルト状態(`no`)に設定しておくと`ssh-add`で登録した秘密鍵も利用して認証を試みるので、基本的には`yes`にしておくほうが意図しない挙動とならない
### ssh接続時に`Load key "/home/user/.ssh/hoge_id_rsa": error in libcrypto`というエラー
``` bash
Load key "/home/user/.ssh/hoge_id_rsa": error in libcrypto
user@address: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```
これは秘密鍵のファイルがおかしい場合(例えば、コピペミスで区切り文字のハイフンの個数が足りていないなど)
``` bash
$ file bad_id_rsa
bad_id_rsa: ASCII text
$ file good_id_rsa
good_id_rsa: PEM RSA private key
```
なお、`bat`コマンドでも色がつくので違いがわかる
秘密鍵の正しい形式
```
-----BEGIN RSA PRIVATE KEY-----
......
-----END RSA PRIVATE KEY-----
```
### VSCodeのsshではgit情報を裏で処理しているための負荷が発生する
[Visual Studio CodeでのSSH接続により、EC2サーバーが高負荷になり動かなくなった - エキサイト TechBlog.]( https://tech.excite.co.jp/entry/2022/09/27/153341 )
### sshの接続が遅い
認証鍵を利用する際にDNSアクセスがあるため、DNSの指定がおかしいと遅くなるケースがある
[ubuntu - SSH by key incredibly slow - Server Fault]( https://serverfault.com/questions/692449/ssh-by-key-incredibly-slow )
#### 鍵を使わずにssh ログインしたいときのsshオプション
``` bash
ssh -o PubkeyAuthentication=no $IP_ADDR
```
## ssh-agent
### ssh-agentの設定
`eval $(ssh-agent)`の中身(macの場合)
``` bash
ssh-agent
SSH_AUTH_SOCK=/var/folders/5d/540y5x9964n8msqxr77rkqr40000gn/T//ssh-91EQWwcjE3lC/agent.93691; export SSH_AUTH_SOCK;
SSH_AGENT_PID=93692; export SSH_AGENT_PID;
echo Agent pid 93692;
```
shellごとに、`ssh-agent`を起動するのではなく、一度起動したssh-agentを使い回す方法が良い
参考: [tmux で attach したら ssh-agent が切れる場合 #SSH - Qiita]( https://qiita.com/sonots/items/2d7950a68da0a02ba7e4 )
### ssh-add
`ssh-add`でgitの秘密鍵を複数登録すると最初に追加したキーのみが有効になる
これは、`ssh-agent`がキーの登録順に接続を試し、最初に成功したキーで通信を行うためである
したがって、複数のgitの秘密鍵を`ssh-agent`では管理できない(gitに限った話ではない)
どうしても利用したい場合には、`-d`でキーを個別に除去したり、`-D`で全て除去する必要がある
`ssh-add``-d`での削除には公開鍵情報が必要であり,それは、`ssh-add -L`で見ることができる
下記で`XXX`個目に登録されているキーを削除できる
``` bash
ssh-add -d <(ssh-add -L | cut -d" " -f1,2 | awk 'NR==XXX')
```
削除する際に下記のようなエラーがでても、実際には、そのファイルが存在しても、formatが正しくない時にも下記のメッセージが表示される
```
Bad key file XXX_id_rsa: No such file or directory
```
### 指定したキーが無視されているような挙動となっている
`ssh-add`の結果は`~/.ssh/config``ssh -i`よりも優先されるため、注意
### ⭐ssh接続先でgit cloneしたい
1. ホストマシンでssh-agentに秘密鍵を追加する
下記のコマンドはシェルごとに実行する必要がある
``` bash
eval $(ssh-agent)
ssh-add ~/.ssh/github_id_rsa
ssh-add -L
```
なお、すでにssh接続していた先のサーバにも上記の変更はリアルタイムに反映される(ホストマシンの`ssh-agent`の情報を利用しているためであると推測される)
2. `ssh`コマンドに`-A`オプションをつける or `~/.ssh/config``ForwardAgent yes`を追加する
3. リモートでsshログインして、`ssh-add -L`して確かめてから、`git clone git@github.com:ORG/REPO.git`をする
#### ssh-agentの機能で適切にfetchできなかった原因
まず、`ssh -T git@github.com`で確認する
該当するgitのリモートのアドレスが原因である可能性がある
``` bash
$ git remote -v
origin github.com:ORG/REPO.git (fetch)
origin github.com:ORG/REPO.git (push)
$ git remote set-url origin git@github.com:ORG/REPO.git
$ git remote -v
origin git@github.com:ORG/REPO.git (fetch)
origin git@github.com:ORG/REPO.git (push)
[[_TOC_]]
## 設定ファイル
### `~/.ssh/config`
#### ProxyJump
[多段SSHならProxyJump!さよならProxyCommand | にっしーラボ]( https://nissy-lab.com/blogs/multiple-ssh-proxyjump/ )
#### sshの接続先の名称で処理を振り分けたい
[SSHのDynamic Forwardを気軽に使うTIPS \| Zenn]( https://zenn.dev/hnw/articles/36e70c0980c8786c7154 )
#### [sshをproxy経由でつなぐ \- @znz blog]( https://blog.n-z.jp/blog/2018-08-12-ssh-over-proxy.html )
``` bash
sudo apt-get install -y connect-proxy
```
``` conf
Host github github.com
HostName github.com
User git
IdentityFile ~/.ssh/XXX_id_rsa
ProxyCommand connect -H proxy-XXX.com:10080 %h %p
```
#### sshのpublic key
`~/.ssh/config``IdentityFile`のファイル名+`.pub`のファイルの形式が不正の場合
```
key_load_public: invalid format
```
というメッセージが表示される
ファイル形式が、一見、正しくとも、`~/.ssh/authorized_keys`のように複数のpublic keyが登録されている場合(他のサーバの`authorized_keys`を流用している場合)に、
なぜか秘密鍵を利用したsshアクセスができなくなっている
おそらく、サーバからではなく、localのpublic keyの先頭行と比較して弾いている?
### `~/.ssh/known_hosts`
defaultでhash化されているので、下記を`~/.ssh/config`へ適用するとhash化されなくなる
```
Host *
HashKnownHosts no
```
* [SSHのホスト鍵設定 \- 簡潔なQ]( https://qnighy.hatenablog.com/entry/2017/10/29/220000 )
* [github の IP アドレスをまとめて known\_hosts に登録する — KaoriYa]( https://www.kaoriya.net/blog/2016/07/04/ )
* hash化しないようにすれば,上記のページの通り,`github.com`のすべてのIPアドレスを一括で登録できるようになる
### sshd(/etc/ssh/sshd_config)
#### デフォルト値
`man sshd_config` [sshd\_config\(5\)]( https://www.freebsd.org/cgi/man.cgi?sshd_config(5) )
#### 設定ファイルの文法チェック
``` bash
sshd -t
```
## rootユーザへパスワード入力無しでログイン(鍵不使用)
[linux \- How do I completely remove root password \- Stack Overflow]( https://stackoverflow.com/questions/11700690/how-do-i-completely-remove-root-password )
1. rootのパスワードをなしにする
`passwd -d root`
具体的には`/etc/shadow``root`の行の2番目の項目が空白になっていればOK
`sed -i 's/^root:[^:]\+:/root::/' /etc/shadow`
2. sshdの設定でパスワードなしログインを許可する
`/etc/ssh/cat sshd_config`
```
PasswordAuthentication yes # default: yes
PermitRootLogin yes # default: yes
PermitEmptyPasswords yes # default: no
UsePAM no # default: no
```
各デフォルト設定: [sshd\_config\(5\)]( https://www.freebsd.org/cgi/man.cgi?sshd_config(5) )
`sudo service sshd restart`で再起動する
## ssh中にhang upした場合の対処法
* [SSH Escape Sequences \- Today I Learned]( https://til.hashrocket.com/posts/d909a57428-ssh-escape-sequences )
* [How can I break out of ssh when it locks? \- Ask Ubuntu]( https://askubuntu.com/questions/29942/how-can-i-break-out-of-ssh-when-it-locks )
* [networking \- Why do consoles sometimes hang forever when SSH connection breaks? \- Server Fault]( https://serverfault.com/questions/283129/why-do-consoles-sometimes-hang-forever-when-ssh-connection-breaks )
> There is a "secret" keyboard shortcut to force an exit :~) From the frozen session, hit these keys in order: Enter~. The tilde (only after a newline) is recognized as an escape sequence by the ssh client, and the period tells the client to terminate it's business without further ado.
例えば,2重でsshをしているときには,`<Enter>`, `~`, `~`, `.`を入力すればよい
(`~`の個数番目の`ssh`がcloseされる)
### [Debian/shutdownやrebootするとssh接続の端末がハングする \- Linuxと過ごす]( https://linux.just4fun.biz/?Debian/shutdown%E3%82%84reboot%E3%81%99%E3%82%8B%E3%81%A8ssh%E6%8E%A5%E7%B6%9A%E3%81%AE%E7%AB%AF%E6%9C%AB%E3%81%8C%E3%83%8F%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B )
サーバ側の設定でこの現象を防止することができるらしい
## ポートフォワーディング
[sshポートフォワーディング \- Qiita]( https://qiita.com/mechamogera/items/b1bb9130273deb9426f5 )
`-f`を指定するとbackgroundになり、わかりにくいので、単に、`-N`だけがおすすめ
フォワードする方向は片方向のみであることに注意
### リモートフォワード(リモートからローカルの方向へつなぐ)
`[local] -> [target] <-> [target2]` (矢印の方向にアクセス可能な環境を仮定)
`ssh -N $TARGET -R 8080:localhost:10080`
としたとき
`$TARGET:8080`->`localhost:10080`の方向つながるが、`$TARGET`外から`$TARGET:8080`へのアクセスはできない
`$TARGET`外からアクセスしたい場合は下記の3通り
* A. $TARGET上で`ssh -N $TARGET2 -R 9090:localhost:8080`としてコネクションを追加で貼る必要がある
* `$TARGET2:9090` -> `$TARGET:8080` -> `localhost:10080`となる
* B. `/etc/ssh/sshd_config``GatewayPorts yes`を追加する(`GatewayPorts`のデフォルト値は`no`)
* C. 単に`$TARGET`を経由させずに直接`ssh -N $TARGET2 -R 9090:localhost:10080`
FROM_HOST -> HOST -> TO_HOSTの3wayのようなつなぎ方も可能
``` bash
ssh -N $FROM_HOST -R $FROM_PORT:$TO_HOST:$TO_PORT
```
このとき、両方ともHOSTからsshできればOK(FROM_HOSTからTO_HOSTへssh接続するわけではない)
### ローカルフォワード(ローカルからリモートの方向へつなぐ)
ローカルフォワードのときは下記のオプションを付加すると簡単に指定できる
> -g Allows remote hosts to connect to local forwarded ports. If used on a multiplexed connection, then this option must be specified on the master process.
`ssh -g -L 8080:$TARGET2:10080 $TARGET`
`localhost:8080` -> `$TARGET` -> `$TARGET2:10080`とつながる
> * -f: Requests ssh to go to background just before command execution.
> * -N: Do not execute a remote command. This is useful for just forwarding ports.
`-g`なし
``` bash
$ ss -atn
LISTEN 0 128 ::1:8081 :::*
LISTEN 0 128 127.0.0.1:8081 *:*
```
`-g`あり
``` bash
$ ss -atn
LISTEN 0 128 *:8081 *:*
LISTEN 0 128 :::8081 :::*
```
#### sshを利用しないローカルポートフォワーディング
`ssh -N -L 28080:127.0.0.1:8080 localhost`相当の処理
``` bash
python -m http.server 8080
curl localhost:28080
socat TCP4-LISTEN:28080,reuseaddr,fork TCP4:127.0.0.1:8080
```
socatコマンドのバインド設定では外部からの通信も受け付けるようになっている
``` bash
$ sudo lsof -i:28080
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
socat 75354 user 5u IPv4 0xc9257403876ca107 0t0 TCP *:28080 (LISTEN)
```
### 簡単にポートフォワーディングしてアクセスしたい
よく利用するリモートターゲットの`~/.ssh/config`の接続先に下記のようにまとめて記述しておくと`localhost:xxx`としてアクセスできるので便利(多重に接続してもエラーなし)
```
LocalForward 10000 localhost:10000
LocalForward 10001 localhost:10001
LocalForward 10002 localhost:10002
LocalForward 10003 localhost:10003
LocalForward 10004 localhost:10004
LocalForward 10005 localhost:10005
LocalForward 10006 localhost:10006
LocalForward 10007 localhost:10007
LocalForward 10008 localhost:10008
LocalForward 10009 localhost:10009
```
特に複数のリモートターゲットがある場合には便利
同様のことを実現したい場合にはvscodeのremote sshでリモートターゲットに接続していれば上記相当の処理が自動的に行われる
### firewall機能によって、ローカルIPアドレス(192.168.x.x)でのアクセスが禁止されているときの抜け穴の構築方法(ssh portfowarding利用)
``` bash
# $FIREWALL_MACHINE: firewall機能で制限されているマシンで実行
ssh -N -R $PROXY_MACHINE 10080:localhost:80
# $PROXY_MACHINE: proxyとして利用する適当なマシンで実行する(これは上のremote portforwardingのポート(10080)が基本的にこのプロキシマシンのローカルに制限されるので、それを公開するためのコマンド)(これはsocatコマンドで代用可能である)
ssh -N -g -L 8080:localhost:10080 localhost
```
`$PROXY_MACHINE:8080` => `$PROXY_MACHINE:10080` => `$FIREWALL_MACHINE:80`の方向でネットワークアクセスができる(これでwebsocketのport forwardingができることを確認済み)
## `~/.ssh/config`なしの多段ProxyCommand利用時の注意
[ssh\_config\(5\) \- Linux manual page]( https://man7.org/linux/man-pages/man5/ssh_config.5.html#TOKENS )
`%h`/`%p`などは多段化するときにはエスケープする必要がある(e.g. `%h:%p`, `%%h:%%p`, `%%%%h:%%%%p`)
``` bash
ssh -oProxyCommand='ssh -W %h:%p -oProxyCommand="ssh -W %%h:%%p -oProxyCommand=\"ssh -W %%%%h:%%%%p HOST_A\" HOST_B" HOST_C' HOST_D hostname
```
正しいケース
HOST_A -%%h:%%p-> HOST_B -%h:%p-> HOST_C
の順番で接続する
``` bash
ssh -oProxyCommand='ssh -W %h:%p -oProxyCommand="ssh -W %%h:%%p HOST_A" HOST_B' HOST_C hostname
```
誤ったケース
HOST_A -%h:%p-> HOST_Bで意図せずに接続されてしまうので、
HOST_A -%h:%p-> HOST_Cとなる
``` bash
ssh -oProxyCommand='ssh -W %h:%p -oProxyCommand="ssh -W %h:%p HOST_A" HOST_B' HOST_C hostname
```
## ダイナミックポートフォワード
ssh接続先をsocks proxyサーバとして利用する機能で,firefoxのプロキシ設定をsocksとすることで利用できる(curlならば`--socks5`オプションを利用する)
[ssh DynamicForwardでセキュアなssh接続 \- 自分用メモ]( https://hoshi-sbg.hatenablog.com/entry/2020/03/18/180234 )
## Xをサポートしていない環境でクリップボードのコピーを行う
[Forward your clipboard via SSH reverse tunnels]( https://gist.github.com/dergachev/8259104 )
下記を`~/.ssh/config`に加える(単なる`Host *`では、例えば、git接続時にも適用されてしまうことに注意)
```
Host hoge*
RemoteForward 5556 localhost:5556
```
下記のクリップボードサーバを動かす
``` bash
while true; do nc -l 5556 | xclip -sel clip; done
# start clipboard daemon
if ! pgrep -f clipboard-daemon >/dev/null; then
nohup bash -c "exec -a clipboard-daemon bash -c 'while true; do { nc -d -l 5556 || sleep 1; } | xclip -sel clip; done'" >/dev/null 2>&1 &
fi
```
ssh先のサーバにて
``` bash
function c() {
# way 1
# cat | nc -q0 localhost 5556
# way 2
# cat | telnet localhost 5556
# way 3
# bash -c 'cat > /dev/tcp/127.0.0.1/5556'
# way 4
python3 <(
cat <<EOF
#!/usr/bin/env python3
import socket
import sys
import argparse
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument('host', type=str)
parser.add_argument('port', type=int)
args, extra_args = parser.parse_known_args()
data = sys.stdin.buffer.read()
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((args.host, args.port))
n = client.send(data)
if n != len(data):
print("failed to send data (data len = {}, send data len = {})".format(len(data), n), file=sys.stderr)
client.close()
if __name__ == '__main__':
main()
EOF
) localhost 5556
}
```
## ssh先でterminal経由でファイルをコピー&ペーストしたい
* clipboardを利用する方法
* e.g. base64
* 長すぎると,terminalの挙動がとてつもなく重くなる(zshのpluginの影響であり,bashなら問題ない)
* 短い文字量ならば問題ない
* tarコマンドを利用することで、実行権限付きでファイルをコピーでき、ディレクトリも対象にできる
* ネットワークを利用する方法(一時的なサーバを利用)
* ただし、サーバによっては自由にネットワークへ接続できないことに注意
dotfilesに`pack`コマンドを作成した
## ssh rsa非推奨
[SSH 公開鍵を ssh-rsa から強い暗号に書き換える - Qiita]( https://qiita.com/katzueno/items/4319fffc8b0b0b50d8a6 )
e.g. `ssh-keygen -t ecdsa -b 521`
## tips
### [while内でsshを使うと1回で止まる \- Miuran Business Systems]( http://site.m-bsys.com/error/whileread-ssh )
use `ssh -n` for avoid staling `stdin` (`-n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background.`)
### [sshの鍵を作るときにちょっとだけ気にしたいこと \| Developers\.IO]( https://dev.classmethod.jp/articles/ssh-keygen-tips/ )
`-C ""`を追記することで,hostnameが共通鍵にコメントとしてはいることを防止できる
### ssh上でreboot
rebootの処理自体はsshが親プロセスでどうさするのではないため、セッションが切れても問題ないと考えられる
## トラブルシューティング
### 意図していない秘密鍵が利用される
`IdentitiesOnly` `yes`: IdentityFile で指定した秘密鍵でのみ認証を試みる設定を`~/.ssh/config`へ追加すると良い
デフォルト状態(`no`)に設定しておくと`ssh-add`で登録した秘密鍵も利用して認証を試みるので、基本的には`yes`にしておくほうが意図しない挙動とならない
### ssh接続時に`Load key "/home/user/.ssh/hoge_id_rsa": error in libcrypto`というエラー
``` bash
Load key "/home/user/.ssh/hoge_id_rsa": error in libcrypto
user@address: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).
```
これは秘密鍵のファイルがおかしい場合(例えば、コピペミスで区切り文字のハイフンの個数が足りていないなど)
``` bash
$ file bad_id_rsa
bad_id_rsa: ASCII text
$ file good_id_rsa
good_id_rsa: PEM RSA private key
```
なお、`bat`コマンドでも色がつくので違いがわかる
秘密鍵の正しい形式
```
-----BEGIN RSA PRIVATE KEY-----
......
-----END RSA PRIVATE KEY-----
```
### VSCodeのsshではgit情報を裏で処理しているための負荷が発生する
[Visual Studio CodeでのSSH接続により、EC2サーバーが高負荷になり動かなくなった - エキサイト TechBlog.]( https://tech.excite.co.jp/entry/2022/09/27/153341 )
### sshの接続が遅い
認証鍵を利用する際にDNSアクセスがあるため、DNSの指定がおかしいと遅くなるケースがある
[ubuntu - SSH by key incredibly slow - Server Fault]( https://serverfault.com/questions/692449/ssh-by-key-incredibly-slow )
#### 鍵を使わずにssh ログインしたいときのsshオプション
``` bash
ssh -o PubkeyAuthentication=no $IP_ADDR
```
## ssh-agent
### ssh-agentの設定
`eval $(ssh-agent)`の中身(macの場合)
``` bash
ssh-agent
SSH_AUTH_SOCK=/var/folders/5d/540y5x9964n8msqxr77rkqr40000gn/T//ssh-91EQWwcjE3lC/agent.93691; export SSH_AUTH_SOCK;
SSH_AGENT_PID=93692; export SSH_AGENT_PID;
echo Agent pid 93692;
```
shellごとに、`ssh-agent`を起動するのではなく、一度起動したssh-agentを使い回す方法が良い
参考: [tmux で attach したら ssh-agent が切れる場合 #SSH - Qiita]( https://qiita.com/sonots/items/2d7950a68da0a02ba7e4 )
### ssh-add
`ssh-add`でgitの秘密鍵を複数登録すると最初に追加したキーのみが有効になる
これは、`ssh-agent`がキーの登録順に接続を試し、最初に成功したキーで通信を行うためである
したがって、複数のgitの秘密鍵を`ssh-agent`では管理できない(gitに限った話ではない)
どうしても利用したい場合には、`-d`でキーを個別に除去したり、`-D`で全て除去する必要がある
`ssh-add``-d`での削除には公開鍵情報が必要であり,それは、`ssh-add -L`で見ることができる
下記で`XXX`個目に登録されているキーを削除できる
``` bash
ssh-add -d <(ssh-add -L | cut -d" " -f1,2 | awk 'NR==XXX')
```
削除する際に下記のようなエラーがでても、実際には、そのファイルが存在しても、formatが正しくない時にも下記のメッセージが表示される
```
Bad key file XXX_id_rsa: No such file or directory
```
### 指定したキーが無視されているような挙動となっている
`ssh-add`の結果は`~/.ssh/config``ssh -i`よりも優先されるため、注意
### ⭐ssh接続先でgit cloneしたい
1. ホストマシンでssh-agentに秘密鍵を追加する
下記のコマンドはシェルごとに実行する必要がある
``` bash
eval $(ssh-agent)
ssh-add ~/.ssh/github_id_rsa
ssh-add -L
```
なお、すでにssh接続していた先のサーバにも上記の変更はリアルタイムに反映される(ホストマシンの`ssh-agent`の情報を利用しているためであると推測される)
2. `ssh`コマンドに`-A`オプションをつける or `~/.ssh/config``ForwardAgent yes`を追加する
3. リモートでsshログインして、`ssh-add -L`して確かめてから、`git clone git@github.com:ORG/REPO.git`をする
#### ssh-agentの機能で適切にfetchできなかった原因
まず、`ssh -T git@github.com`で確認する
該当するgitのリモートのアドレスが原因である可能性がある
``` bash
$ git remote -v
origin github.com:ORG/REPO.git (fetch)
origin github.com:ORG/REPO.git (push)
$ git remote set-url origin git@github.com:ORG/REPO.git
$ git remote -v
origin git@github.com:ORG/REPO.git (fetch)
origin git@github.com:ORG/REPO.git (push)
```
\ No newline at end of file