じゃあ、おうちで学べる

本能を呼び覚ますこのコードに、君は抗えるか

SSH クライアント設定入門 for Golang

概要

離れた場所にあるLinuxサーバーをリモート操作する為には、SSHは欠かすことができません。

本記事ではSSHの基本と実装までをやっていきます。

誤まった内容があればnwiizo までご指摘いただければと思います。

SSH の基礎

SSH(Secure Shel)は、遠隔のホスト間の通信でサービスを安全に運用するための暗号化ネットワーク技術です。強力な認証機能と暗号化により、ファイルの転送やリモート操作を安全に行うことができます。Linuxでは、OpenBSDによるOpenSSHが一般的に利用します。

SSHは前述した通り通信の暗号化を行って安全な通信を実現します。たとえば、telnet を使った場合、通信内容はプレーンテキストなので、通信経路を盗聴されると容易にID/PASS が流出するなんてことになりかねません。また、https/http2 や Apache Kafka のその他にも ssl/tls の技術に関して様々な技術の発展をしています。

もう少しの圧倒的な理由としては接続先のホストの正当性を確認できることです。SSHでは、ログインより先にクライアントがサーバーの正当性を確認するホスト認証が行われます。Linuxであれば$HOME/.ssh/known_hosts などに情報が記載されます。そして、接続先が自分が今まで接続していたサーバーかどうかを、接続毎に確認します。

SSHにはサーバー側に sshd ないしはそれに準ずるプロセスが動いている必要があり、皆さんが好きなKubernetes ではsshではなく独自の機構を用いて接続を確立されています。その辺に関してはkubectl execの仕組みを追える範囲で追ってみた などが詳しいのでぜひ見てください。

あと、Linuxsshコマンドが上手くいかない時は-v optionを使えば大体、解決するので困ったら-v optionぐらいに思ってもらえればよいです。

暗号技術について知りたければ暗号技術入門 第3版 秘密の国のアリスをぜひ、読んでください。SSHの歴史やもっと詳しいことが知りたい場合はBulletproof SSL/TLS の日本語書籍である プロフェッショナルSSL/TLS を読むことをオススメします。

接続設定

Golangsshパッケージであるgolang.org/x/crypto/ssh 読めばGolangSSHを書けるようになる。 本当にcrypto: golang.org/x/crypto/sshのドキュメントが優秀なのでここを見れば解決するのですが具体的にどのように使えば良いか分からないことも多いと思うので一つずつ説明していく

ssh.ClientConfig SSHサーバーに接続情報を登録する

golang.org/x/crypto/ssh を使ってsshクライアントを実装していくときにはサーバーへの接続の為にはClientConfigを設定が必要となる。これらの設定によって

config := &ssh.ClientConfig {
  User: "username",
  Auth: []ssh.AuthMethod{ 
    // ... 
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

鍵認証が必要な場合はAuthMethod にて指定する必要があります。

config := &ssh.ClientConfig {
  User: "username",
  Auth: []ssh.AuthMethod{ 
    publickey("mykey")
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

パスワード認証やパスワード付き鍵認証にも対応していますがパスワードが情報として入っているコードは非常に怖いのでos.Getenvkelseyhightower/envconfig環境変数として受け取るのが良い。

config := &ssh.ClientConfig {
  User: "username",
  Auth: []ssh.AuthMethod{ 
    ssh.Password(pass)
  },
  HostKeyCallback: ssh.InsecureIgnoreHostKey(),
}

kevinburke/ssh_config というパッケージがありこれは現状利用しているssh_config を読み込んでsshの接続情報として利用できるパッケージでありこれらによってN台に接続が必要な場合に必要になる yamlやtomlの設定情報がぐっと減るのでオススメである。

user := ssh_config.Get(host, "User")

微妙に書いてるブログがあるので興味があれば見てみてください参照してみてください。これらで設定は終わりです。次に接続してみます。

conn, err := ssh.Dial("tcp", addr, config)
defer conn.Close()

これにより、認証、キー交換が実行されます。このSSH接続で何か行うには、セッションを作成する必要があります。セッションが作成されると、セッション上でsession.Runで単一のコマンドを実行できます。

    session, err := conn.NewSession()
    if err != nil {
        log.Println(err)
    }
    defer session.Close()

    //Check whoami
    var b bytes.Buffer
    session.Stdout = &b
    remote_command := "/usr/bin/whoami"
    if err := session.Run(remote_command); err != nil {
        log.Fatal("Failed to run: " + err.Error())
    }
    log.Println(remote_command + ":" + b.String())
}

これらをログに出すなり変数に入れるなり標準出力して自由に楽しんでいきましょう。

最後に

徹底というほど入門記事として機能するか分かりませんが利用背景と接続方法までは書けたとおもうのでこの記事がどこかの誰かの為になることを祈ります。golang.org/x/crypto/ssh を読みましょう