個人的に Goでsshのクライアントコマンド を作ってるのだけど、ssh接続で使用している処理が肥大化してメンテナンスが辛くなってきたので、ライブラリとして外出しすることにした。

以下のようなことが簡単にできるように作ってある。 細かい使い方については GoDoc を参照してもらえれば…(´・ω・`)。

  • ログインシェルへの接続(Ctrl+Cとかタブ補完もできる)
  • ターミナルログの取得(タイムスタンプ付与)
  • sshやhttp,socks5の多段プロキシ接続
  • x11 forwarding
  • port forwarding
  • pkcs11認証(Yubikeyとかの物理...

Goでsshのクライアントコマンドを作ってるのだが、それにx11 forwarding機能を実装したかったのでいろいろと調べてみた。 で、以下のような通信の流れになっているので、それを踏まえて実装してみた。

  1.  sshクライアント=>sshサーバ: sshクライアント側からsshサーバ側に、「SSH_MSG_CHANNEL_REQUEST」でx11-reqを送る(RFC4254)
  2.  sshサーバ: x11の初期化処理が行われる(sshサーバ側のDISPLAY環境変数にlocalhost:6000+x11ディスプレイ番号が入り、ポートが開く)
  3.  sshサーバ => sshクライ...

最近は、Goで自作してる sshクライアントコマンド(lssh) の機能追加を主にやってる(で、こっちあまり更新してない(´・ω・`))。

実はちょっと前、下のようなツールを見かけて、それと同じようなことが自作のsshクライアントやりたいと思って機能追加していたのだけど、それがやっとできるようになった。 これが何なのかというと、sshで複数のノードにパラレル接続して、そのままプロンプト上からインタラクティブにコマンドを流せるというツールで、便利そうだしすごくかっこよさげなのだ。

An interactive parallel ssh client featuring autocom...


自作のsshクライアントコマンドで~/.ssh/configを読み込んで処理させる機能を追加したかったのだが、ProxyCommandがネックになっていたため今まで実装を見送っていた。 で、久しぶりになんか情報ないかなと探してみたところ、net.Pipe()を利用したら処理できるという情報を見かけた。

ProxyCommandはローカルで実行するコマンドになるので、そのコマンドの出力をPipeで繋げていけばいいようだ。なるほど…(´・ω・`)。 というわけで、さっそく実装してみた。こんな感じのコードで.ssh/configから指定したホストの情報を取得して、かつProxyCommand...


OpenSshサーバでは、特定のCA証明書が署名した証明書(+秘密鍵)で認証ができるように設定することができるらしい。 (自前のsshクライアントに機能を追加する際のテストサーバ用途ではあったのだけど)実際にやってみたので、備忘で残しておくことにする。

1. CA(秘密鍵、公開鍵)とユーザ(秘密鍵、公開鍵)の用意

まず当たり前の話ではあるのだが、CAの鍵とユーザの鍵の2種類が必要になるのでそれをまず作成する。(CA側・ユーザ側ともにすでに作成済の場合は飛ばしてしまってOK) CA側は管理者が署名をするための鍵なので1個だけ、ユーザ側は各ユーザが利用するためのものなのでユーザの数だけ...


ここ最近、仕事が変わったのと Rustでこさえてたツール の改修に手間取っててあまり触ってたなかったのだけど、ある程度一段落したので Goのsshクライアントの改修 に着手した。 で、sshでの接続方式というといくつかあると思うが、最近はYubikeyをPIVカードとして利用して、Yubikey内の秘密鍵を使ってssh接続するというやり方もあるので、それをGolangで実装しようと思いやってみた。

これ、実はかなり手間取ってしまい、結構時間がかかってしまった…。 Yubikey等のPIVカードに入ってる秘密鍵を使ってssh接続する場合、OpenSCなどのPKCS11を扱えるライブラ...


前回、goでssh-agentをForwardingする処理について書いたことがあったけど、認証自体は普通にパスワードで処理するように書いていた。で、ssh-agentで認証させることもできるようなので、サンプルコードを書いてみた。

以下、サンプル(一応 こちら にもあげている)。


Mac OSで、ssh-agentにYubikeyの鍵を登録したいということがあったので、備忘で残しておく(すでにOpenSCとかはインストール済で、ssh -Iでログインができる状態と仮定)。 ssh-agentでYubikeyの鍵を利用する場合、通常であればssh-agent起動後、以下のようなコマンドを実行すればいい。

ssh-add -s /usr/local/lib/opensc-pkcs11.so

Twitterをぼけーっと見てたとき、こういう処理についてどうやって実現するかって内容を見かけたので、ちょっと調べてみた。

ローカルのWSLで処理を完結するならclip.exeとかを使えば良さそうなのだけど、sshでリモートに接続してたりするとこの方法は使えない。 じゃどうするかというと、ローカルでX Window Serverを立ち上げて、ssh接続先でxclipからクリップボードにコピーすればいいようだ。 リモートマシンにパッケージ入れないといけないのがちょっと抵抗ありそうだけど、調べた限りこれが一番シンプルそう。

以下、ざっくりとした流れ


自前で作ってるGolangで書いたsshクライアント に、ssh-agentの機能を追加できないかなと思い調べてみたところ、ライブラリがすでに用意されているようで結構簡単に実装できそうだということがわかった。 というわけで、ssh-agentで鍵を転送できるsshクライアント(ターミナル接続可能)のサンプルコードを書いてみる。

以下、そのコード。ソースは こちら にもあげている。


自前で作ってるGolang製のsshクライアントにssh port forwardingを追加したくなったので、まずはサンプルコードを書いてみることにした。 StackOverflowにちょうどいいサンプルがあったので参考にさせてもらったところ、ターミナルセッションとは別にsshの接続をする必要がありそうだ。ポートフォワード自体はio.Copyで対応できるようだ。

以下、サンプル( こちら にもおいてある)。


Yubikey 4に秘密鍵を入れてssh接続に利用する

個人的に、sshの接続は基本的には公開鍵認証を使うようにしている。

で、秘密鍵はローカルマシンで保持させてるのだけど、Yubikeyに秘密鍵を入れて、証明書認証の設定をすることでトークン認証にすることもできるようだ。 確かに、これなら複数のマシンで共通の秘密鍵を利用できるし、PINコードでの認証も必要になるので、2要素認証的な要素もあってセキュリティも固くなる。

触ってみないとなんともいえないので、ひとまずは実際に試してみることにした。なお、Yubikeyから鍵を取得するため、OpenSCが必要になるらしい。 ssh接続先にはCentOS 7、Ubuntu Server 18.04 L...


前回、sshからsuでユーザを切り替えて、ログインユーザではないユーザから直接コマンドを実行させるという内容について記述していたが、この方法だとttyの払い出しがなされないということに気づいた。

sshから直接suコマンドでユーザを切り替えてコマンドを-cオプションで実行させる場合、残念ながら仮想端末が有効にならないし、そのためのオプションというのも用意されていない。 じゃあどうすればいいかというと、scriptコマンドを経由することで仮想端末が使えるようになるので、それを利用する。


ローカルorリモートマシン(ssh)でsuによるユーザ切り替え時に自動でパスワード入力をさせる

諸事情があり、sudoを使わずにsuだけでユーザを切り替えてコマンドを実行したい、その時にパスワードの入力をキーボードから行わずに自動化させたいということがあったので、調べてみた。 こういった場合、ヒアドキュメントを使えば指定した入力は標準入力として扱われるので、それでパスワードの入力が自動化できる(ただ、テキストとして丸見えになるし、(psの出力には残らないけど)historyにも残るので自己責任で…)。


WSLでリモートマシンに接続してポートフォワーディングする場合、Teratermのようにメニューから選択等をする必要はなく、普通にsshコマンドから実行してやればいいようだ。

ssh -L <ローカルポート番号>:<対象ホスト名:対象ポート番号> user@hostname

WSL単体でできるってのは、なかなかいいものだなと。 …あまり使う機会なさそうだけど(´・ω・`)。


ちょっと前に、ssh接続時にローカルのrcファイルをそのまま読み込ませる方法について書いたけど、それと組み合わせられるようにインクリメンタルサーチ用のシェル関数で「boco」というものを作ってみた。これはANSIエスケープコードを利用してプロンプト下に標準入力で受け付けた内容を出力させて選択した内容を標準出力で表示させるシェル関数で、外部コマンドとしてgrepとsort、あとはbashの機能のみで動作するように作成している。 あまりにも受け付けた入力が大きすぎる場合は挙動が重くなるが、10000件くらいなら問題なく処理できるので、historyのインクリメンタルサーチくらいなら利用でき...


先日、 ssh接続先でローカルのbashrcを使うシェル芸 というのを書いたのだが、同じような方法を使えばvimrcやtmuxの設定ファイルも持っていけることに気づいた。 bashの--rcfileオプションのように、vimでも-uオプションで使用するvimrcファイルを指定できるので、bashと同じようにプロセス置換を利用してやればいい。

ただ、vimrcやtmux.confの場合、bashrcのように1回だけ読み込ませればそれでおしまいにはならない。 コマンドを実行するたびに設定ファイルを読み込むことになるので、起動してつなげっぱなしのbashとはすこしやり方が異なる。 vim...


ふと、ローカルにあるbashのrcファイルを、ssh接続先で一時ファイルを作成せずに利用できないかなーと思ったので調べてみた。 で、調べた結果bashには実行時に指定したPATHのrcファイルを読み込むオプション(--rcfile)があるのがわかった。 であれば、ssh接続時にそのコマンドを実行し、さらにローカルファイルの内容をプロセス置換でファイルとして読み込むようにssh越しに渡してやればいけるということになる。

ssh -t user@host 'bash --rcfile <(echo "'"$(cat ./path/to/local.rc)"'")' # そのまま渡す場合
s...

ちょっと前に Golangでsshの多段プロキシSocks5プロキシ経由での接続について調べたが、今回はhttpプロキシ経由の場合どうするのかについて調べてみた。

残念ながらhttpプロキシ経由の通信(CONNECTメソッドを利用したプロキシ)で*net.Connを取得できるライブラリは無いようで、そのあたりについては書かないとならないようだ。 幸いにも サンプルコード を書かれている人がいたので、それを使ってhttpプロキシを経由したssh接続のコードを記載する。

実行可能なコードはこちらにもおいてある。

ssh_term_http_proxy.go
...

Golangでsshへの接続を行う際、ssh proxyはどうやってやるんだろうと思ったんで調べてみた。 実装は結構簡単で、以下のように一度Proxyにsshでログイン後、ログイン対象サーバへの接続をProxyで作成してやるという流れでいけるようだ。

抜粋。動作するコードはこちらに記載。

ssh_term_proxy.go
// proxy1の情報 proxy1Host := "proxy1.host.local" proxy1Port := "22" proxy1User := "user" proxy1Pass := "pass...

前にGolangでsshクライアントを作る際、どうにも制御キーをうまく渡せずに致し方なくsshコマンドを実行させるような処理を書いてたのだけど、ちょっと前に見かけたsshwというツールのソースを見てたところ、sshコマンドを実行せずにそのあたりが正常に動いていた。 で、なんでだろうと調べて見たところ、どうやら ssh/terminal.MakeRaw() 等を使ってうまくそのあたりを実装していたようだ。

こちらにもソースを上げてるのだけど、以下サンプル。

term_ssh.go
package main import ( "fmt" "os"...

awsに接続してssh_configを生成するec2sshというツールがあるのだけど、awsやazコマンドで得たjsonをjqで加工して似たようなことができそうだなと思ったのでやってみた。 awsの場合は、以下のようにaws-cliでec2の情報を取得してjqに渡してやればいい。ユーザ名は取得できないので、必要であればjqの処理のとこに(決め打ちになってしまうが)追記してやればいい。

aws ec2 describe-instances | jq -r '.Reservations[].Instances[]|(.Tags[]|select(.Key == "Name")|.Value...

たまーにsshで直接コマンドを実行する事があるのだが、この場合だと擬似端末(pty)が有効にならない。 こうなると、authorized_keysなどで実行できるコマンドを制限している際、擬似端末が無いと挙動がおかしくなるようなプログラムを実行させる時にちょっと困る事がある。

blacknon@BS-PUB-UBUNTU-01:~$ env | grep -i tty
SSH_TTY=/dev/pts/0
blacknon@BS-PUB-UBUNTU-01:~$ ssh blacknon@bs-pub-ubuntu-02
blacknon@bs-pub-ubuntu-02's passwo...

scpを使う場合、サーバ側にもscpがインストールされて無いといけないのだけど、ごくたまにscpがインストールされていない場合がある。 そんなときは、以下のようにすることでsshコマンド経由でファイルのやり取りをすることができる。

単体ファイルの場合

cat file | ssh user@host 'cat > ./file' # リモートサーバにコピーする場合
ssh user@host 'cat ./file' | cat > ./file # リモートサーバからコピーする場合

sshというと22番ポートを利用するものだが、環境によっては利用できない事がある。 で、そういった場合だと443番ポート(SSL)を利用する場合が多いのだが、Webサーバなんかの場合だとすでにhttpsで使用している場合が多い。 そんなとき、sshとsslを443番ポートで同居させて、それぞれのパケットのときは適切に割り振りをしてくれるリバースプロキシのような動作をしてくれるのが『SSLH』になる。

1. インストール

CentOSやDebian系のOSを使っている場合は簡単で、yum(epelが必要)やaptからインストールが可能だ。

Debian/Ubuntu系の場合

s...

先日、ssh接続する際に.ssh/configで指定していた鍵ではない秘密鍵を使って接続しようとしてたところ、公開鍵を登録していない秘密鍵を指定しても接続されてしまうという事があった。 なんだこりゃと思って-vオプションを付与して見たところ、以下のような動きをしていた。

blacknon@BS-PUB-DEVELOP:~$ cat .ssh/config
Host 192.168.0.119
HostName 192.168.0.119
User root
Port 22
IdentityFile /home/blacknon/.ssh/id_rsa
blacknon@BS-PUB-D...

時折、リモートサーバにある"ログインユーザでは読み取りができないファイル"をそのままローカルにコピーしたいことがある。 ssh経由でファイルをコピーするといえばscpがよく使われる方法だと思うが、残念ながらscpではリモートサーバ側でsudoを使ってroot権限でファイルを読み込んだりといった事はできない。 さて、じゃどうすればいいのだろうか。

こういったとき、sudoをNOPASSWDで実行可能な状態であれば、単体のファイルであればsshコマンドからsudoを使ってcatで、ディレクトリごとであれば一度tarでアーカイブ化してローカルでそのまま展開させる事ができる。 なお、RHEL系のデ...


Microsoft Azure上で鍵認証でLinuxを使っているのだが、諸事情によりログイン用の秘密鍵を紛失してしまうといったことがあった。 流石に何処かにはあるだろうと色々と探したのだけど、どうしても見つからない。 どうすりゃいいかなぁ…と調べていたところ、Azureポータルの対象VMを選択すると「パスワードのリセット」なる項目が。 藁にもすがる思いでそこから公開鍵を登録してみることにした。