BluemixとカスタムドメインとSSLサーバー証明書とクライアント証明書

Bluemixではカスタムドメインを登録し、カスタムドメインをhttpsで保護するためのSSLサーバー証明書を登録することができます。またクライアント証明書トラストストアを登録することによりクライアント認証にも対応します。

本記事ではBluemixのSydneyリージョンにカスタムドメイン"sydney.takeyan.xyz"を登録し、このドメインに対してSSLサーバー認証、クライアント認証を有効化した際の作業手順をご紹介します。動作確認が目的なので、証明書はopensslで自己署名して作成しています。

Bluemixのトライアルアカウントでは、証明書のアップロード操作は１回しかできないという制約があります。一発勝負ですので慎重にどうぞ。

##手順
1. DNSにカスタムドメインの地域エンドポイントを登録する
2. SSLサーバー証明書を作成する
3. クライアント証明書を作成しトラストストアに格納する
4. Bluemixにカスタムドメインを登録し証明書をアップロードする
5. カスタムドメインを経路に指定してアプリを作成する
6. ブラウザにクライアント証明書を登録する
7. httpsでカスタムドメインのアプリにアクセスする


##1. DNSにカスタムドメインの地域エンドポイントを登録する
Sydneyリージョン用カスタムドメイン"sydney.takeyan.xyz"を、対応する地域エンドポイントに関連づけてDNSに登録します。

Bluemixのオンラインマニュアルには次のように書かれています。

> _カスタム・ドメインを使用する場合、SSL 証明書を提供するために、 以下の地域エンドポイントを使用して、Bluemix で組織に割り振られた URL 経路を指定します。_

> * _US-South: secure.us-south.bluemix.net_
> * _EU-GB: secure.eu-gb.bluemix.net_
> * _AU-SYD: secure.au-syd.bluemix.net_

今回はSydneyリージョンを使うことにしたので、地域エンドポイントはsecure.au-syd.bluemix.netを選択します。
DNSには\*.sydney.takeyan.xyzというホスト名でsecure.au-syd.bluemix.netという値のCNAMEを追加します。ホスト名はワイルドカード（\*.で始まる名前）にしてあります。

お名前.comでのCNAME登録例：
<img width="738" alt="スクリーンショット 2016-08-17 23.25.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/1d6598dd-6a5e-c42d-db6f-6bd23cc10cb6.png">

検証はしていませんが、DNSにCNAMEを登録しなくても、hostsファイルで代用できるようです。その場合はhostsファイルにアプリのホスト名（今回の例ではnr.sydney.takeyan.xyz）と、対応する地域エンドポイントのIPアドレス（pingやnslookupで確認できます）を記入して下さい。

##2. SSLサーバー証明書を作成する

ubuntu 14.04LTS環境での実行例を紹介します。あらかじめ最新のopensslをインストールしておきます。

```bash
sudo apt-get update
sudo apt-get install openssl
```

opensslをインストールしたら、まずSSLサーバー証明書を作成します。
①カスタムドメイン用秘密鍵(sydney_takeyan.key)生成、②証明書署名要求（sydney_takeyan.csr）生成、③秘密鍵のパスフレーズ保護を解除、④証明書署名要求を秘密鍵で自己署名して証明書(sydney_takeyan.crt)生成、の順に実行します。

```
① openssl genrsa -des3 -out sydney_takeyan.key 2048

② openssl req -new -key sydney_takeyan.key -out sydney_takeyan.csr

③ cp sydney_takeyan.key sydney_takeyan.key.org
③ openssl rsa -in sydney_takeyan.key.org -out sydney_takeyan.key

④ openssl x509 -req -days 365 -in sydney_takeyan.csr -signkey sydney_takeyan.key -out sydney_takeyan.crt
```
②では対話式に入力を求められます。ここでCommon Nameとしてワイルドカード付のカスタムドメイン名（ここでは\*.sydney.takeyan.xyz）を指定して、任意のホスト名に対応するワイルドカードSSLサーバー証明書にします。以下に実行例を抜粋して掲載します。

```
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Kyoto
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Takeyan Sydney
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:*.sydney.takeyan.xyz
Email Address []:

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

##3. クライアント証明書を作成しトラストストアに格納する
作成手順は基本的にはSSLサーバー証明書と同様です。複数のクライアント証明書に対応できることを確認するため、クライアント証明書は２個作成して2個ともトラストストアに格納します。

①client1用秘密鍵(client1_takeyan.key)生成、②証明書署名要求（client1_takeyan.csr）生成、③証明書署名要求を秘密鍵で自己署名して証明書(client1_takeyan.crt)生成、④PKCS#12形式の鍵ストアファイル(client1_takeyan.p12)に秘密鍵と証明書を格納、の順に実行します。

```
① openssl genrsa -des3 -out client1_takeyan.key 2048

② openssl req -new -key client1_takeyan.key -out client1_takeyan.csr

③ openssl x509 -req -days 365 -in client1_takeyan.csr -signkey client1_takeyan.key -out client1_takeyan.crt

④ openssl pkcs12 -inkey client1_takeyan.key -in client1_takeyan.crt -export -out client1_takeyan.p12
```

以下に②の対話入力の実行例を抜粋して掲載します。

```
Country Name (2 letter code) [AU]:JP
State or Province Name (full name) [Some-State]:Kyoto
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Takeyan Sydney
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:client1.takeyan
Email Address []:

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

client2についても同様の手順を実行します。

```
① openssl genrsa -des3 -out client2_takeyan.key 2048

② openssl req -new -key client2_takeyan.key -out client2_takeyan.csr

③ openssl x509 -req -days 365 -in client2_takeyan.csr -signkey client2_takeyan.key -out client2_takeyan.crt

④ openssl pkcs12 -inkey client2_takeyan.key -in client2_takeyan.crt -export -out client2_takeyan.p12
```


その後、⑤PKCS#7形式のクライアント証明書トラストストアファイル(clienttruststore_takeyan.p7b)に2つの証明書を格納します。

```
⑤ openssl crl2pkcs7 -nocrl -certfile client1_takeyan.crt -certfile client2_takeyan.crt -out clienttruststore_takeyan.p7b
```

参考まで、ここまでに作成したファイルの一覧を掲載します。

```
seiichi@devops:~/sydney$ ls -l
合計 52
-rw-rw-r-- 1 seiichi seiichi 1139  8月 18 11:40 client1_takeyan.crt
-rw-rw-r-- 1 seiichi seiichi  972  8月 18 11:40 client1_takeyan.csr
-rw-rw-r-- 1 seiichi seiichi 1751  8月 18 11:39 client1_takeyan.key
-rw-rw-r-- 1 seiichi seiichi 2405  8月 18 11:41 client1_takeyan.p12
-rw-rw-r-- 1 seiichi seiichi 1139  8月 18 11:43 client2_takeyan.crt
-rw-rw-r-- 1 seiichi seiichi  972  8月 18 11:43 client2_takeyan.csr
-rw-rw-r-- 1 seiichi seiichi 1751  8月 18 11:42 client2_takeyan.key
-rw-rw-r-- 1 seiichi seiichi 2405  8月 18 11:43 client2_takeyan.p12
-rw-rw-r-- 1 seiichi seiichi 2277  8月 18 11:44 clienttruststore_takeyan.p7b
-rw-rw-r-- 1 seiichi seiichi 1151  8月 18 11:37 sydney_takeyan.crt
-rw-rw-r-- 1 seiichi seiichi  980  8月 18 11:35 sydney_takeyan.csr
-rw-rw-r-- 1 seiichi seiichi 1675  8月 18 11:37 sydney_takeyan.key
-rw-rw-r-- 1 seiichi seiichi 1743  8月 18 11:37 sydney_takeyan.key.org
```

##4. Bluemixにカスタムドメインを登録し証明書をアップロードする

BluemixコンソールでリージョンをSydneyに切り替えます。Sydneyの使用が初めての場合はスペースの作成を求められるので、適当にスペース名を定義します。リージョンを切り替えたら以下の手順に従って証明書をアップロードします。

Manage Organizations（組織の管理）を選択します。
![スクリーンショット 2016-08-18 17.22.16.png](https://qiita-image-store.s3.amazonaws.com/0/32083/e62bafe8-feee-13fe-2b50-930289d3e9f0.png)



View Details（詳細を表示）→ Edit Org（組織の編集）の順にクリックします。
![スクリーンショット 2016-08-18 17.28.52.png](https://qiita-image-store.s3.amazonaws.com/0/32083/35275f17-5671-72f6-dc99-510e08a20caa.png)


DOMAINS（ドメイン）を選択し、ADD DOMAIN（ドメインの追加）でカスタム・ドメインを追加します。
![スクリーンショット 2016-08-18 17.31.29.png](https://qiita-image-store.s3.amazonaws.com/0/32083/a253d7ce-44f4-11cc-c9cf-50f40e0f32bb.png)



カスタム・ドメイン名 sydney.takeyan.xyz を入力してSAVE（保存）します。
※ここではワイルドカードは使いません。
![スクリーンショット 2016-08-18 17.33.21.png](https://qiita-image-store.s3.amazonaws.com/0/32083/4b4784d6-bba5-b3c7-edc1-7a36cde7f726.png)


Upload Certificate（証明書のアップロード）をクリックします。
![スクリーンショット 2016-08-18 17.34.57.png](https://qiita-image-store.s3.amazonaws.com/0/32083/35607313-0211-ba91-3046-ee24b1c0ca1c.png)


Upload Certificate（証明書のアップロード）の画面で以下のように値を指定して、UPLOAD（アップロード）をクリックします。

* Certificate（証明書） → sydney_takeyan.crt
* Private Key（秘密鍵） → sydney_takeyan.key
* Enable request of client certificate（クライアント証明書の要求の有効化） → チェック
* Client Certificate Trust Store（クライアント証明書トラストストア） → clienttruststore_takeyan.p7b
![スクリーンショット 2016-08-18 17.37.10.png](https://qiita-image-store.s3.amazonaws.com/0/32083/2e117203-1fa4-bd51-aae0-6203fecac1f4.png)



証明書のアップロードが完了して、アップロードのアイコンがバッジの絵に変わりました。
![スクリーンショット 2016-08-18 17.39.50.png](https://qiita-image-store.s3.amazonaws.com/0/32083/a1bb1b7a-4a5e-5098-de9d-d3f48fe9de6e.png)
（※試行錯誤中の経験ですが、ここでエラーメッセージが返ることもあったのですが、アップロード処理自体は無事完了していました。一発勝負なのでエラーメッセージが返っても諦めず、念の為コンソールをリロードしてカスタムドメインの状態を確認してみて下さい。）

バッジのアイコンをクリックすると、アップロードしたサーバー証明書の情報が表示されます。
<img width="1220" alt="スクリーンショット 2016-08-18 17.43.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/177425bc-a57d-1565-2567-f533569f560d.png">



##5. カスタムドメインを経路に指定してアプリを作成する

カスタム・ドメインを経路に指定してアプリケーションをひとつ作成します。ここではNode-RED Starterボイラプレートを選択して、App Nameはnrとし、Domainで今回登録したカスタムドメイン名 sydney.takeyan.xyz を選択しました。
![スクリーンショット 2016-08-18 17.45.29.png](https://qiita-image-store.s3.amazonaws.com/0/32083/80cde652-bec8-60c2-d74c-923585196ce4.png)

![スクリーンショット 2016-08-18 17.47.48.png](https://qiita-image-store.s3.amazonaws.com/0/32083/b5c2829f-1ef3-14f1-3efd-4411bd225a0c.png)

経路の指定以外は通常のアプリ作成手順と同様なので詳細は省略します。


##6. ブラウザにクライアント証明書を登録する

FireFoxにクライアント証明書を組み込みます。FireFoxで「設定」→「詳細」→「証明書」→「証明書を表示」で証明書マネージャーを開き、「あなたの証明書」で「インポート」を選択します。
![スクリーンショット 2016-08-18 17.53.57.png](https://qiita-image-store.s3.amazonaws.com/0/32083/69fdd3d2-5213-2898-e4f9-5d1d5821ea68.png)

![スクリーンショット 2016-08-18 17.56.17.png](https://qiita-image-store.s3.amazonaws.com/0/32083/ded0ecee-a510-3e37-a5e9-15eb74d16628.png)


先ほど作成したクライアント証明書の鍵ストアファイル client1_takeyan.p12を選択します。
![スクリーンショット 2016-08-18 17.58.05.png](https://qiita-image-store.s3.amazonaws.com/0/32083/b38a8451-4025-cd6d-0fb5-d3b8d25589ad.png)


パスワードを要求してくるので、鍵ストアファイル作成時に指定したパスワードを入力します。
<img width="1233" alt="スクリーンショット 2016-08-18 17.59.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/49227524-2bf8-5f73-61d9-5c17fbf9be1e.png">


クライアント証明書がFireFoxに組み込まれました。
<img width="1233" alt="スクリーンショット 2016-08-18 18.02.05.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/37482ab0-83dd-688d-20a3-a457d2d9435c.png">


##7. httpsでカスタムドメインのアプリにアクセスする

クライアント証明書を登録したブラウザから、先ほど作成したアプリ（ここでは https://nr.sydney.takeyan.xyz ）を呼び出します。Bluemixのカスタムドメインの設定で「クライアント証明書の要求の有効化」にチェックしたことにより、接続要求の際にBluemixがクライアント証明書を要求してきて、コレを受けてFireFoxは証明書確認のため「個人証明書の要求」のポップアップを表示します。
<img width="1234" alt="スクリーンショット 2016-08-18 20.43.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/45efdded-b8ce-d741-fe05-6f3406e7f131.png">

個人証明書の要求のポップアップで、選択した証明書が正しいこと（CNがclient1.takeyanであること等）を確認してOKをクリックします。
BluemixとFireFoxの間でクライアント認証処理が完了して先に進むと、今度は「安全な接続ではありません」の警告メッセージが表示されます。
<img width="1234" alt="スクリーンショット 2016-08-18 20.47.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/0f6d26c1-119b-f934-d5b8-4f3d40bc0eb2.png">


これは自己署名サーバー証明書に起因する事象（サーバー証明書の署名者が、ブラウザが信頼する認証局ではないため）であり、想定通りの警告です。「エラー内容」→「例外の追加」→「セキュリティ例外を承認」でサーバー証明書をブラウザに信頼させることで対応します。
<img width="1232" alt="スクリーンショット 2016-08-18 20.49.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/b3fdcb73-c015-ce43-3bd0-3fbde4a668a1.png">




https://nr.sydney.takeyan.xyz を呼び出した後、クライアント認証、サーバー証明書の受け入れを経て接続処理が完了し、ようやくNode-REDの初期画面が表示されました。
<img width="1221" alt="スクリーンショット 2016-08-18 20.50.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/32083/32967221-b546-3a7c-82d6-a7cae9a2218f.png">

「安全な接続ではありません」のエラーメッセージは2回目の接続要求からは表示されません。個人証明書の要求のポップアップは接続要求の度に表示されますが、FireFoxの場合は証明書の設定でサーバーが個人証明書を要求したときの動作を「自動的に選択する」にしておけば、このポップアップも表示しなくなるようです。


以上です。


参照： 
https://new-console.ng.bluemix.net/docs/manageapps/secapps.html
http://www.tonyerwin.com/2014_09_01_archive.html
https://langui.sh/2009/03/20/creating-a-pkcs7-p7b-using-openssl/