nginx で クライアント認証したい！- ベーシック認証の置き換え

# 必要なものは全てここにある

http://server-setting.info/centos/private-ca-cert.html

・・・だけだと終了してしまうので、もろもろ追記。
（まだ整理できてない箇所もあるので、違ってたら突っ込みお願いします）

# そもそもクライアント認証って？

そもそもの発端は、「社内で使っていた管理画面を外部業者に委託したい」という所から。
社内限定であればIPベースのFW（AWSならセキュリティグループ）の設定で事足りてたのですが、いざ外部に公開となると、IP制限では対応しきれない...！

当然ベーシック認証も設定はしてあるものの、アタックされる可能性もなきにしもあらず。

そこで！ベーシック認証の代替手段として、「クライアント認証」の登場です。

仕組みはこういう（[SSL：クライアント認証](http://alk.dip.jp/apache2-default/sv290.html) ）ページを見て頂いた方が早いのですが、平たく言うと **証明書を持った特定の端末（厳密にはブラウザ）からしかアクセスできない** 認証方法となります。

証明書が漏れた場合はその証明書を失効させる事もできるため、セキュリティ的にはベーシック認証と比べかなり安心安全です。

# 用語の整理

まず最初の壁がここ。聞き慣れない（見慣れない）単語が多くて萎縮して発狂しないようにするために用語の整理。

| 用語 | 別の言い方 | 説明 | 内訳 |
|:-----------|:-----------|:-----------|:-----------|
|CA| Certificate Authority, 認証局|「この人ダイジョブ」ってサーバ証明書の信頼性の責任持つ人。証明書の保証人みたいな。保証人の保証人もいる（＝中間CA）|-|
|ルートCA| ルート認証局|保証人の保証人の...を辿っていった一番最後の人。他の保証人がいないので、証明書は **オレオレ** です。Verisign とか comodo とか Symantec とかがこれにあたる|-|
| CSR | Certificate Signing Request|認証局に「サインくれ」っていうために書く申請書みたいなもの。証明書を設置するサーバ側が発行する|「サーバの公開鍵」＋「組織名とか所在地とか」|
| CRT  | CeRTification（の略。恐らく。）, SSL証明書, サーバ証明書|いわゆるサーバ証明書（後で補足予定）|（「CSR」＋「CAのサイン」）→CA秘密鍵で暗号化|

# クライアント認証のためにやること

最初の link の概略になりますが。処理の流れは以下↓

1. openssl をインストールする
2. 認証局（＝プライベートCA）を自前で作る
3. サーバ証明書を作成する。そして自分で作ったCAでサインする。
4. クライアント証明書を作成する。そして自分で作ったCAでサインする。
5. クライアントに証明書を渡して、ブラウザにインストールする。
6. nginx の設定をする

# 諸注意

## 4. クライアントに証明書をインストールする

### `PKCS#12` ファイルの作成

`PKCS#12` ファイルは、クライアントに配布するためのパッケージファイルです。
中身は以下の３点が入っており拡張子は `.p12` となります。
※上記のリンクは拡張子が `.pfx` となってますが、[同じもの](http://d.hatena.ne.jp/lars_t/20100313/1268501773)っぽい？
- クライアント証明書
- クライアント秘密鍵
- 認証局証明書

上記のリンクの方法（4-4）だとプライベートCAの証明書が入っていないので、３点含めて `pkcs#12` に変換します。
`newcert.pem`, `newreq.pem` がカレントディレクトリにある状態で、次のコマンドを実行します。

```
# /usr/lib/ssl/misc/CA.sh -pkcs12
Enter Export Password: PKCS#12 保護用パスワードを入力（何でも可能）
Verifying - Enter Export Password:
```

`CA.sh`は内部的には `openssl` を実行しているので、もし↑の `CA.sh` でエラーが出た時は愚直に `openssl` コマンド叩くしかないです。

```
# openssl pkcs12 -nokeys -in newcert.pem -inkey newreq.pem -certfile /path/to/cacert.pem -out newcert.p12 -export -name "My Certificate"
```


### クライアント側のインストール

上記で作成した `PKCS#12` ファイルを、何かしらの方法でクライアント認証をしたい端末に送ります。

後は最初のリンクの「[（おまけ）プライベート認証局を登録（インポート）する](http://server-setting.info/centos/private-ca-cert.html#firefox_12)」の項目とほぼ一緒です。
読み込むファイルを指定した時にパスワードを聞かれるので、先ほど `PKCS#12` ファイルを作成した時に使ったパスワードを入力してください。

プライベートCAを読み込んだあと、以下のチェックボックスを忘れずに有効にしてください。
<img width="308" alt="スクリーンショット 2015-12-29 20.08.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/8963/1ab1a4be-9879-372d-6639-e8d45c117f75.png">

### 対応クライアントを増やすには

4, 5 をやればよいはず。


## 5. nginx 側の設定


```conf
server {
  listen 443 ssl; # ssl on; ではなく、listen に書くのが推奨

  server_name foo.example.com;

  # server certificate
  ssl_certificate /etc/ssl/CA/certs/foo.example.com.crt; # サーバのSSL証明書。3.で作ったもの
  # server private key
  ssl_certificate_key /etc/ssl/CA/private/foo.example.com.key; # サーバの秘密鍵。3.で作ったもの

  ssl_verify_client on; # クライアント認証しまっせ
  # ssl_verify_depth 2; # 中間CA を使う場合のみ

  # CA certificate
  ssl_client_certificate /etc/ssl/CA/capem.pem; # プライベートCAの証明書。2.で作ったもの

  location ~ /foo {
    # as you like
  }

}
```

設定後、nginx の再起動を忘れずに。

## 参考

http://www.ssl-concier.com/news/topics/164
http://d.hatena.ne.jp/install-memo/20110906/1315291837
http://server-setting.info/centos/private-ca-cert.html
http://vimtaku.github.io/blog/2014/03/16/apache-nginx-client-certificate/
http://www.nslabs.jp/pki-client-certification-with-nginx.rhtml
http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_client_certificate