プログラマでありたい

おっさんになっても、プログラマでありつづけたい

意外に便利。Apache+https+SVNでクライアント証明書で認証。或いは、クラウド・スマホ時代の開発環境の一形態

 どの辺りに需要があるのか解りませんが、SVNのリポジトリにSSL経由でアクセスする際の認証をクライアント証明書で行う方法です。割りとサクっと出来るので、メモがてらに残しておきます。とりあえずSubversionの例で話していますが、クライアント証明書で認証を行うというのは地味に便利です。id+passでの認証より、恐らく安全性は高いと思います。

クライアント証明書とは?

 そもそもクライアント証明書とは何でしょうか?クライアント証明書は個人用証明書とも呼ばれて、その名前の通りクライアントが誰かと証明する代物です。ご存知の通り、個人の証明にはID,Passwordが一般的です。ただこれだとID,パスワードの管理の問題や漏洩、代理ログインの問題があります。これに対して、クライアント証明書はPCなりスマートフォンにインストールするので、管理や漏洩の問題は小さいです。
 ちなみにクライアント証明書は昔からあるけど、あまり使う機会がない代物だったのかもしれません。一方、最近はスマートフォンの普及でMDM(モバイルデバイス管理)が急速に普及してきたので、耳にする機会も増えたのかもしれません。

必要なもの

  • Apache Httpd
  • mod_ssl
  • mod_dav_svn
  • Open SSL
  • Subversion

インストール

上記の各モジュールをインストールします。
Redhat/CentOS系だと、yumで一発です。

yum install httpd mod_ssl mod_dav_ssl subversion openssl

オレオレ証明局(CA)の立ち上げ

# vi /etc/pki/tls/openssl.cnf

v3_ca

basicConstraints = critical,CA:true


CAの証明書の作成

# cd /etc/pki/tls/misc/
# ./CA -newca
CA certificate filename (or enter to create)

Making CA certificate ...
Generating a 2048 bit RSA private key
......+++
.............................................................+++
writing new private key to '/etc/pki/CA/private/./cakey.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Osaka
Locality Name (eg, city) [Default City]:Osaka
Organization Name (eg, company) [Default Company Ltd]:dkfj test
Organizational Unit Name (eg, section) []:dkfj test
Common Name (eg, your name or your server's hostname) []:dkfj
Email Address []:hoge@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
Using configuration from /etc/pki/tls/openssl.cnf
Enter pass phrase for /etc/pki/CA/private/./cakey.pem:
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number:
            9c:da:d3:b2:64:56:49:c7
        Validity
            Not Before: Feb 11 10:49:49 2012 GMT
            Not After : Feb 10 10:49:49 2015 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Osaka
            organizationName          = dkfj test
            organizationalUnitName    = dkfj test
            commonName                = dkfj
            emailAddress              = hoge@example.com
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                6B:DA:63:AE:9F:33:68:B4:91:EB:C1:27:E3:74:46:A6:B4:A3:7F:BA
            X509v3 Authority Key Identifier: 
                keyid:6B:DA:63:AE:9F:33:68:B4:91:EB:C1:27:E3:74:46:A6:B4:A3:7F:BA

            X509v3 Basic Constraints: 
                CA:TRUE
Certificate is to be certified until Feb 10 10:49:49 2015 GMT (1095 days)

Write out database with 1 new entries
Data Base Updated


証明証を作ったので、元に戻しておきます。

# vi /etc/pki/tls/openssl.cnf

v3_ca

#basicConstraints = critical,CA:true

秘密鍵と証明書要求ファイル(CSR)の作成

 秘密鍵と証明書要求ファイルを作成します。これは、どこで作っても良いです。まぁ同じサーバで作るのが楽でしょう。

$ openssl genrsa -out username-client.key 1024
$ openssl req -new -key username-client.key -out username-client.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Osaka
Locality Name (eg, city) [Default City]:Osaka
Organization Name (eg, company) [Default Company Ltd]:dkfj test
Organizational Unit Name (eg, section) []:dkfj test
Common Name (eg, your name or your server's hostname) []:username.local
Email Address []:username@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

デジタル証明書(crt)の作成

# openssl ca -out username-client-ca.crt -infiles username-client.csr 
パスワードを入力して、Yesを2回

ブラウザで使う為のPKCS#12の作成

# cat username-client.key username-client-ca.crt  | openssl pkcs12 -export -out username-client.p12 -name "Username client key"
Enter Export Password:
Verifying - Enter Export Password:

Apacheの設定

ssl.confを編集します。

vi /etc/httpd/conf.d/ssl.conf
SSLCACertificateFile /etc/pki/tls/certs/my-ca.crt
SSLVerifyClient require
SSLVerifyDepth  10


 特定のパスのみ適応させたい場合は、SSLVerifyClient requireを全体ではなくディレクティブ内のみに設定します。ちなみに、SSLRequireSSLとSSLVerifyClientの違いは、次のようになっています。
・SSLRequireSSL:接続をSSLに限定する
・SSLVerifyClient:CA局が発行した証明書を持つユーザーのみがhttpsに接続可能となる


SVNのリポジトリの公開例です。
証明書+ID,Pass認証をしています。

<Location /repos>
   DAV svn
   SVNParentPath /var/www/svn

   # Limit write permission to list of valid users.
   <LimitExcept GET PROPFIND OPTIONS REPORT>
      # Require SSL connection for password protection.
       SSLRequireSSL
       SSLVerifyClient require

      AuthType Basic
      AuthName "Authorization Realm"
      AuthUserFile /path/to/passwdfile
      Require valid-user
   </LimitExcept>
</Location>

ブラウザの設定

IE の場合:
 作成した、*.p12ファイルをクライアント側のPCにダウンロードしてください。
FireFoxの場合:
 ツール -> オプション -> 詳細タブ -> 暗号化タブ -> 証明書を表示 -> あなたの証明書タブ -> インポート
Chrome:
 IEの証明書をつかうので、インポートしていれば大丈夫です。


 使い勝手の話なんですが、意外に便利です。
開発サーバがローカルのネットワークではなく、クラウド上のサーバ等に移動していることは多々あると思います。その時に公開するものの制限によっては、アクセス制限なし・基本認証等のアクセス制限・証明書によるアクセス制限・証明書+アクセス制限・VPNによる遮蔽と色々なレベルがあると思います。証明書だけ入れておけばいいよというレベルのアクセス制限ってのも意外にあるので、利便性の向上につながるのではないでしょうか?特にスマートフォンの開発等では?(オレオレ証明書の壁を超える対策が必要ですが。)


参考:
HTTPS + SVN でクライアント証明書を使ってみよう : アシアルブログ