オブジェクトストレージ30日間無料
ドキュメントご利用ガイドOpenSSHの認証に証明書を使う方法

OpenSSHの認証に証明書を使う方法

2014/10/09 18:00

OpenSSHの認証に証明書を使う方法

「これは2015年5月17日以前にアカウント登録されたお客様向けの記事です。」



導入

OpenSSHはUNIX系サーバのリモートログインの手段として、幅広く使われています。ConoHaのVPSでも、起動したVPSではOpenSSHが動作していて、コントロールパネルからダウンロードした秘密鍵を使用してVPSにログインすることができます。サーバの管理をする場合、OpenSSHはほぼ必須と言っていいでしょう。

今回はOpenSSHの認証方式の一つである、証明書による認証を紹介します。この方式はバージョン5.4からサポートされました。OpenSSHの認証によく使われるのはパスワード認証と公開鍵認証かと思いますが、証明書を使用した認証はまだあまり一般的ではないように思います。詳細は後ほど解説しますが、証明書による認証は、CA(認証局)の鍵を信用し、CAによって署名された証明書を持つユーザ/ホストを認証する方式です。パスワード認証や公開鍵認証のように、ユーザ/ホストを個別に認証する必要がなくなります。証明書というとSSL証明書の発行を想像される方も多いと思いますが、技術的な仕組みは非常によく似ています。

以下はOpenSSHのユーザ認証とホスト認証がどのように実行されるのかを簡単にまとめたものです(ユーザ認証、ホスト認証については、エントリーの中程でおさらいします)

公開鍵認証 証明書による認証
ユーザ認証 ユーザの公開鍵をサーバ上のauthorized_keysファイルに追加する。サーバは乱数を生成し、ユーザの公開鍵で暗号化し送信。ユーザは暗号鍵で復号し乱数のハッシュ値を計算、それをサーバに送信。サーバはハッシュ値を照合する。 あらかじめユーザの公開鍵にCAが署名をする。またサーバはCAの公開鍵を保持する。ユーザは接続時に署名済みの公開鍵(証明書)を送信し、サーバはそれを検証する
ホスト認証 ユーザの接続時に、サーバは自身の公開鍵とフィンガープリントを送信する。ユーザはそれを確認し、公開鍵を受け入れるかを決める あらかじめサーバの公開鍵にCAが署名をする。ユーザはCAの公開鍵を保持しており、接続時にサーバから送信された署名済みの公開鍵(証明書)を検証する。

証明書による認証は、以下のようなケースで有用な場合があります。
 ・ 多数のサーバがあり、ユーザ追加のたびにサーバに公開鍵を登録するのが面倒
 ・ 多数のユーザがいて、公開鍵の登録/削除が面倒
 ・ しかしLDAPを構築するのも面倒

また、以下のようなことが可能です
 ・ ユーザをログイン禁止にしたい(証明書の失効)
 ・ ユーザに有効期限を設定したい(証明書に有効期限を設定する)
 ・ 実際のユーザと、ログイン可能なシステムユーザを分けて管理したい(Principalsの設定)
 ・ ユーザ毎にポートフォワード(port-forwarding)やエージェント転送(agent-forwarding)の許可をしたい

エントリをご覧いただくに当たり、公開鍵暗号の基礎知識や、PKI(公開鍵暗号基盤)の理解が必要です。ConoHaと同じGMOインターネットグループのGMOグローバルサインのWebサイトに解説があります。併せてご覧ください。

[PKI・証明書入門]
https://jp.globalsign.com/service/knowledge/

また、OpenSSH(ssh-keygenコマンド)のマニュアルに、証明書の項があります。こちらもご覧ください。

[SSH-KEYGEN (1)]
http://www.unixuser.org/~euske/doc/openssh/jman/ssh-keygen.html#証明書


ホスト認証とユーザ認証

まずはおさらいです。OpenSSHの認証には、ホストを認証するものとユーザを認証するものがあります。(ホストとはVPSなどの接続先のサーバのことです)。すでにご存じの方は読み飛ばしてください。


ユーザ認証
ホストが接続してきたクライアントを認証します。例えば、クライアントがホストに接続し、ユーザ名とパスワードを送信して、ホスト側ではそれが一致するかを検証するものです。これはわかりやすいと思います。


ホスト認証
ユーザ認証の逆で、クライアントが接続先のホストを認証します。これは接続先ホストの正当性を確認するもので、例えば悪意のある第三者がクライアントサーバの間に中継サーバを立て、通信を傍受するなどを防ぐものです。

sshで初めて接続するホストに接続したとき、以下のようなメッセージを見たことがありませんか?

# ssh user@hostname
Certificate invalid: name is not a listed principal
The authenticity of host '******** (***.***.***.***)' can't be established.
RSA key fingerprint is **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**.
Are you sure you want to continue connecting (yes/no)?

これは、接続先ホストの公開鍵がまだクライアントでは確認できていないと言うことです。OpenSSHでは、公開鍵暗号の仕組みを利用してホストを認証します。これはクライアント側の仕事です。

具体的には、フィンガープリントが表示されているので、ホストの管理者に公開鍵のフィンガープリントを確認して一致することを確認します。そして、一致するならばyesを選択し、ホストの公開鍵をknown_hostsファイルに保存します。一度公開鍵がknown_hostsに保存されれば、次回の接続時からはこのメッセージは表示されなくなります。


証明書とCA

それでは本題に入っていきます。ここから、クライアント(ユーザ)、CA、ホスト(サーバ)という3者が登場します。本来この3者は別々の立場になりますが、今回は全て自分で作業することになります。一つのマシン上での作業ですが、今自分がどの立場で作業しているかを常に意識するようにしないと、混乱してしまうかもしれません。注意してください。

また、今回は解説が目的なので、CAの構築と接続先のホストを同じVPSを使います。これも本来は別であるべきです。

検証環境は、ConoHaの標準OSであるCentOS6.5です。


CAの鍵ペアを作成する
まずは、公開鍵に署名を行い証明書を発行するCAを作りましょう。

CAが使う鍵ペアを作成します。これはユーザの公開鍵や、ホストの公開鍵に署名するのに使用されます。VPS上の適当なディレクトリに移動し、ssh-keygenコマンドでキーペアを作成しましょう。今回はホームディレクトリのcaと言うディレクトリにしました。

mkdir ~/ca
cd ~/ca
ssh-keygen -f conoha-ca.key

こうすることで、caディレクトリ内にconoha-ca.keyとconoha-ca.key.pubという二つのファイルができます。前者が秘密鍵、後者が公開鍵です。

CAの作成はこれで終わりです。


ユーザ認証を行う

それでは証明書を使った認証を試してみましょう、まずはユーザ認証からです。

ユーザは公開鍵認証を使うときと同じように鍵ペアを作成し、CAに公開鍵を提出します。CAはユーザの公開鍵に対して署名をして、証明書をユーザに返却します。一方ホスト側には、あらかじめCAの公開鍵を登録しておきます。クライアントはホストに接続した際、CAによって署名された公開鍵を提出します。ホスト側は提出された公開鍵がCAによって署名されていることを検証することで認証をします。


ユーザ側の作業
まずはユーザが使う鍵ペアを作成します。ここではUnix系OSのコマンドから作成することを想定していますが、Windwosなどの場合は各ツールの方法に従ってください。

キーの作成にはssh-keygenコマンドを使用します。

ssh-keygen -f conoha-client.key

conoha-client.keyとconoha-client.key.pubという二つのファイルが作成されます。.pubの方が公開鍵です。

次に公開鍵をCAに提出します。公開鍵をscpコマンドでVPSに転送します。

scp conoha-client.key.pub root@[VPSのアドレス]:~/ca

ここからCA側の作業になります。提出された公開鍵に署名をして、証明書を作成します。この場合は、rootユーザでログイン可能な365日間有効な証明書を作成することになります。

cd ~/ca
ssh-keygen -s conoha-ca.key -I test-certificate -n root -V +365d conoha-client.key.pub

見慣れないオプションが多数出てきました。それぞれの意味は以下のようになります。
 ・ -s: 署名に使用する秘密鍵を指定します。今回はCAの秘密鍵ファイルを指定します。
 ・ -I: 公開鍵に署名する際のSpecify(詳細)を指定します。証明書を使った認証をしたときに、ホスト側この内容がログに記録されます。
 ・ -n: Principalを指定します。ここで指定したUNIXユーザ名でのみログインができます。カンマ区切りで複数の指定が可能です。
 ・ -V: 証明書の有効期限を指定します。(省略可)

(注意) CentOS6.5に含まれるOpenSSH-5.3p1では、-nオプションではなく-Zオプションになっています。manページの表記も間違っているので注意してください。CentOS7では修正されています。 https://bugs.centos.org/view.php?id=6904

すると、conoha-client.key-cert.pubと言うファイルが作成されます。-certはCertificateの略で、証明書ファイルであることを表しています。

正しく作成されているか、証明書の内容を確認してみましょう。ssh-keygenコマンドの-Lオプションを使用します。

ssh-keygen -L -f conoha-client.key-cert.pub

出力は以下のようになります。

conoha-client.key-cert.pub:
        Type: ssh-rsa-cert-v01@openssh.com user certificate
        Public key: RSA-CERT **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**
        Signing CA: RSA **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**
        Key ID: "test-certificate"
        Serial: 0
        Valid: from 2014-10-07T15:11:00 to 2015-10-07T15:12:17
        Principals: 
                root
        Critical Options: (none)
        Extensions: 
                permit-X11-forwarding UNKNOWN OPTION (len 0)
                permit-agent-forwarding UNKNOWN OPTION (len 0)
                permit-port-forwarding UNKNOWN OPTION (len 0)
                permit-pty UNKNOWN OPTION (len 0)
                permit-user-rc UNKNOWN OPTION (len 0)

Validが有効期間で、365日になっています。Principalsにはrootとあるので、この証明書はrootユーザでのログインが可能なことを示しています。

内容に問題なければ、この証明書ファイルをクライアントに転送します。

scp root@[VPSのアドレス]:~/ca/conoha-client.key-cert.pub

クライアント側の作業は完了です。次にホスト側の作業です。


ホスト側の作業
ホスト側ではsshd_configにCAの公開鍵を設定します。設定したCAによって署名された証明書を持つユーザに、ログインを許可するようになります。

まずCAの公開鍵をホストに転送します。今回は同サーバ上にあるのでコピーするだけです。

cp ~/ca/conoha-ca.key.pub /etc/ssh

sshd_configを編集します。

vi /etc/ssh/sshd_config

以下の行を追加します。

TrustedUserCAKeys /etc/ssh/conoha-ca.key.pub 

設定を変更したので、sshdをリスタートします。

service sshd restart

これで準備が整いました。


ログインする
ログインの前に、ちゃんとファイルがあるか確認してみましょう。

ls

以下の3つのファイルがあるはずです。

conoha-client.key conoha-client.key-cert.pub conoha-client.key.pub>

ではログインしてみましょう。sshコマンドの-iオプションで、最初に作成したクライアントの秘密鍵を指定します。こうすることで自動的に証明書が使用されます。また、証明書が使われていることを確認するため、-vオプションでデバッグ情報を表示させています。

ssh -v -i conoha-client.key root@[VPSのアドレス]

ログインできましたか? ログインできたなら、デバッグ情報に以下のような出力があるはずです。

debug1: Offering RSA-CERT public key: conoha-client.key
debug1: Server accepts key: pkalg ssh-rsa-cert-v01@openssh.com blen 1094
debug1: ssh_rsa_verify: signature correct

“Offering RSA-CERT public key”となっているのがポイントです。(ちなみに、公開鍵認証の場合は”Offering RSA public key”となります)


ホスト認証を行う

次にホスト認証です。こちらはUnix系OSが前提になります。証明書でホスト認証を行うメリットは、クライアント側にCAの公開鍵を登録することで、CAが署名した証明書を持ったサーバに接続する際に、公開鍵の検証をしなくて済むことです。


ホストの公開鍵に署名する
OpenSSHはデーモンとして起動する際に、設定ファイルでホストの公開鍵を指定します。ただ最近のOSの場合は、起動スクリプトなどがこれを自動的に行ってくれることが多いようです。例えばCentOS6.5の場合、/etc/sshの内容を見てみましょう。

ls -l /etc/ssh

典型的には、以下のファイルがあります。

-rw-r--r-- 1 root root 2047 10月  6 12:44 2014 ssh_config
-rw------- 1 root root  668 10月  6 12:44 2014 ssh_host_dsa_key
-rw-r--r-- 1 root root  590 10月  6 12:44 2014 ssh_host_dsa_key.pub
-rw------- 1 root root  963 10月  6 12:44 2014 ssh_host_key
-rw-r--r-- 1 root root  627 10月  6 12:44 2014 ssh_host_key.pub
-rw------- 1 root root 1675 10月  6 12:44 2014 ssh_host_rsa_key
-rw-r--r-- 1 root root  382 10月  6 12:44 2014 ssh_host_rsa_key.pub
-rw-r--r-- 1 root root 3875 10月  6 12:44 2014 sshd_config

ssh_host_dsa_key.pubとssh_host_rsa_key.pubがホストの公開鍵です。CAはこれらのファイルに署名を行います。なおホスト認証では、IPアドレスではなくホスト名が認証の対象です。証明書にホスト名が書き込まれ、そのホスト名でのみ認証がされるからです。

ConoHa VPSではデフォルトで、「v123-123-123-123.z1s2.static.cnode.jp」のようなホスト名が割り当てられます。これをそのまま使ってみましょう。

cd ~/ca
cp /etc/ssh/ssh_host_dsa_key.pub /etc/ssh/ssh_host_rsa_key.pub .
ssh-keygen -s conoha-ca.key -I conoha-ssh-server -h -n `hostname` -V +365d ssh_host_dsa_key.pub
ssh-keygen -s conoha-ca.key -I conoha-ssh-server -h -n `hostname` -V +365d ssh_host_rsa_key.pub

ユーザ認証の時と同じようですが、-hオプションが増えています。これはホスト認証をする証明書を作成するオプションです。hostnameの部分は自動的にホスト名に置き換えられます。

正しく作成されているか、証明書の内容を確認してみましょう。ユーザ認証の時と同じ異様に、ssh-keygenコマンドの-Lオプションを使用します。出力は以下のようになります。

ssh_host_rsa_key-cert.pub:
        Type: ssh-rsa-cert-v01@openssh.com host certificate
        Public key: RSA-CERT **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**
        Signing CA: RSA **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**
        Key ID: "conoha-ssh-server"
        Serial: 0
        Valid: from 2014-10-07T17:19:00 to 2015-10-07T17:20:49
        Principals: 
                v***-***-***-***.static.cnode.jp
        Critical Options: (none)
        Extensions: (none)

Principalsに正しくホスト名があることを確認してください。問題なければ、これらのファイルを/etc/sshに戻します。

cp ssh_host_dsa_key-cert.pub ssh_host_rsa_key-cert.pub /etc/ssh

sshdの設定を変更する
作成した証明書を使用するため、sshd_configを変更します。以下の行を追加してください。

HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
HostCertificate /etc/ssh/ssh_host_dsa_key-cert.pub

設定ファイルを変更したので、sshdをリスタートします。

service sshd restart

ホスト側の設定はこれで完了です。


クライアント側の設定
クライアント側での作業は、known_hostsファイルにCAの公開鍵を登録することです。これにより、CAによって署名された証明書を持つサーバを認証することができるようになります。

まずはCAの公開鍵を確認しておきます。ホスト上で以下のコマンドを実行することで確認できます。

cat ~/ca/conoha-ca.key.pub

次にクライアント側でknown_hostsファイルを編集します。ただ、このエントリの内容を試された方は、おそらくすでにホストの公開鍵が登録されていると思われるので、known_hostsファイルをリネームして新規に作成しましょう。

cd ~/.ssh
cp known_hosts _known_hosts_backup
vi ~/.ssh/known_hosts

新規に以下の行を書き込みます。

@cert-authority v***-***-***-***.static.cnode.jp ssh-rsa AAAAB3NzaC1....

@cert-authorityという固定キーワードに続き、接続先ホスト名、CAの公開鍵、となります。

これでクライアント側の設定は完了です。


接続してみる
では、ホスト認証が正しく行われていることを確認してみましょう。-vオプションでデバッグ情報を表示させています。[ホスト名]のところはIPアドレスを指定すると失敗しますので注意です。

ssh -v root@[ホスト名]

以下の出力があることを確認しましょう。

debug1: Server host key: RSA-CERT **:**:**:**:**:**:**:**:**:**:**:**:**:**:**:**
debug1: Host 'v***-***-***-***.static.cnode.jp' is known and matches the RSA-CERT host certificate.
debug1: Found CA key in /Users/***/.ssh/known_hosts:1
debug1: ssh_rsa_verify: signature correct

known_hostsの1行目の公開鍵で署名が検証できたことになります。これで成功です。
ここで公開鍵を保存するか尋ねるメッセージが表示された場合は、何か設定が間違っています。もう一度確認してみてください。


おわりに

証明書を使った認証をご紹介しました。パスワード認証や公開鍵認証に比べると、設定などがやや煩雑な印象を受けます。しかし、ユーザやホストを個別に認証するのではなく、CAによって署名されたユーザ/ホストを認証するという大きな違いがあることもわかりました。

冒頭でお話ししたとおり、大量のユーザ/ホストを運用するときの、認証の複雑さを回避するために、有効な方法の一つであると言えるでしょう。ConoHa VPSだけでなくサーバ運用全般で活用できると思いますので、試してみてください。

今すぐお申し込み