5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

富士通クラウドテクノロジーズAdvent Calendar 2019

Day 10

ニフクラに登録したSSHキーと手元のキーが一致しているか確認する

Last updated at Posted at 2019-12-09

これは、「富士通クラウドテクノロジーズ Advent Calendar 2019」の10日目の記事です。

はじめに

ニフクラには、作成されるサーバーに初期登録されるSSHの公開鍵をアップロードする機能があり、コントロールパネル公式CLIツールを活用 して、手元で作った公開鍵をサーバーに登録することができます。
SSHキーはリージョン毎に管理されているため、最低でも利用するリージョン数、サーバーによって異なるキーを使う場合はその分だけ管理するキーが増えていき、不要になったカギを整理するうちに、「手元とニフクラコンパネのSSHキーが一致しない!このキーってなんだっけ?」ということになるわけです。(なるわけです)

ニフクラコンパネやAPI取得できる「フィンガープリント」の値を使って、ニフクラに登録されたSSHキーと手元のキーを確認することができるので、その方法をまとめておきたいと思います。

image.png

対象読者

(ニフクラユーザー || ニフクラ開発者 ) && ( Linux を CUI で操作できる人 )

「SSH フィンガープリント」で検索すると出てくるであろう下記の方法では、
残念ながら「ニフクラのフィンガープリント」と一致する値は得られません。

ssh-keygen -lf <ssh の公開鍵 (e.g. path/to/id_rsa.pub )>
ssh-keygen -l -E md5 -f <ssh の公開鍵 (e.g. path/to/id_rsa.pub )>

「ニフクラのフィンガープリント」とは?

ニフクラのドキュメントを探すと、 DescribeKeyPairs API のドキュメントページ に記載がありました。
読み解くと実は、「ニフクラフィンガープリント」とは、「DER形式のSSH公開鍵の情報の MD5 Hash値」の事を指すそうです。

DER とは、バイナリファイルのフォーマットの一種で、鍵や証明書をASN.1 というデータ構造で表現し、それをシリアライズしたものだそうです。※出典

鍵や証明書を保存したものとしては他にも「PEM」形式と呼ばれるものがあります。
PEM形式は、「.PEM/.pem」という拡張子に使われており、見覚えのある人も多いのではないでしょうか。
ニフクラ上でSSHキーを作成する機能を使うと、秘密鍵がこのPEM形式でダウンロードできます。

ちなみに PEM とは?

鍵や証明書を保存したものとしては他にも「PEM」形式と呼ばれるものがありますが、こちらは、鍵や証明書を↑と同じように ASN.1 形式で表し、それを Base64 エンコーディングしたものとなります。
こんなの

-----BEGIN RSA PRIVATE KEY-----
6KyO44Gu5paH5a2X5YiX6KyO44Gu5paH5a2X5YiX6KyO44Gu5paH5a2X5YiX
772e5Lit55Wl772e6KyO44Gu5paH5a2X5YiX6KyO44Gu5paH5a2X5YiXCg==
-----END RSA PRIVATE KEY-----

実際にはもっと長いです。最初と最後の行が特徴的。

SSH公開鍵認証では秘密鍵を表現するのに利用されますし、 HTTPS 通信などで利用される SSL 証明書も PEM 形式で取り扱われることもあります。

実装

Linux の Shell コマンドで確認する

秘密鍵から「ニフクラのフィンガープリント」を確認する

DescribeKeyPairs API のドキュメントページ の記載を読み解くと、下記のコマンドで「ニフクラのフィンガープリント」が得られることがわかりました。

$ openssl rsa -in id_rsa -pubout -outform DER | openssl md5 -c
writing RSA key
(stdin)= 70:6c:67:f5:32:be:14:4b:c3:37:fd:bf:49:df:3c:18

コマンドの内容を確認すると、

  1. OpenSSL コマンドでSSH秘密鍵を読み込み、公開鍵をDER形式で出力
  2. パイプから受け取った標準出力のmd5値を出力

という処理になっていることがわかります。
パイプの後は、 md5sum コマンドを使っても問題ありません。

※実験用に鍵にはパスフレーズを設定していません。パスフレーズが設定されている場合は DescribeKeyPairs API のドキュメントページ の通り、

openssl rsa -in <path/to/id_rsa> -pubout -outform DER -passin pass:<password> | openssl md5 -c

としてください。

SSHの認証に利用する秘密鍵から公開鍵の「ニフクラのフィンガープリント」を取り出していますから、たいていの場合は↑で事足りますね。

公開鍵から「ニフクラのフィンガープリント」を確認する

一応、公開鍵から「ニフクラのフィンガープリント」を計算する方法も併記しておきます。
秘密鍵には公開鍵の情報が含まれているため、遊び程度の意味しかありませんが...

SSHで利用される公開鍵には様々な形式があるかと思いますが、 ssh-keygen で生成される .pub 形式の公開鍵は OpenSSH 独自のフォーマットとなっています。

こういうやつ

ssh-rsa AAAAB~~~~~ root@ubuntu

このままでは openssl コマンドでは読み込めないため、形式を変換して利用します。

ssh-keygen -f id_rsa_pass.pub -e -m PKCS8 | openssl rsa -pubin -pubout -outform DER | openssl md5 -c

用途があるかは不明ですが、公開鍵からも「ニフクラのフィンガープリント」を確認することができます。

Golang のプログラムで確認する

自分が最近 Golang を使ったプロダクトの開発に携わっているので、ちょっと調べてみました。

秘密鍵から「ニフクラのフィンガープリント」を確認

package main

import (
        "crypto/md5"
        "crypto/rsa"
        "crypto/x509"
        "fmt"
        "io/ioutil"
        "os"

        "golang.org/x/crypto/ssh"
)

func main() {
        filePath := "./id_rsa"
        f, err := os.Open(filePath)
        if err != nil {
                fmt.Println(err)
                return
        }
        defer f.Close()

        // PEM 形式の秘密鍵を読み込む
        privateKeyPEM, err := ioutil.ReadAll(f)
        if err != nil {
                fmt.Println(err)
                return
        }

        // PEM 形式から interface{} 型として秘密鍵を取り出す
        privateKey, err := ssh.ParseRawPrivateKey(privateKeyPEM)
        if err != nil {
                fmt.Println(err)
                return
        }

        // interface{} 型から rsa.PrivateKey 型にキャスト
        rsaPrivateKey, ok := privateKey.(*rsa.PrivateKey)
        if !ok {
                fmt.Println("error")
                return
        }
        err = rsaPrivateKey.Validate()
        if err != nil {
                fmt.Println("error")
                return
        }

        // DER 形式で公開鍵を取り出す
        publicKeyDer, _ := x509.MarshalPKIXPublicKey(&rsaPrivateKey.PublicKey)

        // DER 形式の公開鍵のMD5ハッシュ値を計算する
        publicKeyDerMd5Sum := md5.Sum(publicKeyDer)

        fmt.Printf("%x\n", publicKeyDerMd5Sum)
}

openssl コマンドでの手順と同様に、

  1. SSH秘密鍵を読み込む
  2. DER形式で公開鍵を取り出す
  3. MD5ハッシュ値をとる

という手順で値を取り出します。

おわりに

「ニフクラのフィンガープリント」と手元の秘密鍵が一致しているかを調べようとして、「SSH フィンガープリント」と検索して「罠」に嵌ってしまったところからこの記事につながりました。

MD5などのハッシュ関数を利用した、データをユニークに特定する不可逆な値を「フィンガープリント」と呼ぶらしいのですが、SSHの文脈だとすでに使われており混乱してしまいましたが、おかげで SSH の公開鍵認証の仕組みを調べて理解を深めることができました。

同じように困っている方の一助となれば幸いです。

明日は、 @kenta_ojapi が 「営業からエンジニアへ転向して思ひしことを徒然に綴ろうかな」という興味深い記事を書いてくれるみたいです。お楽しみに。

5
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?