SSL自己署名証明書作成（webサーバ：Apache）

# Goal

```
* 社内でのみ使うツールの通信を暗号化するために、SSLを導入する
* ユーザは関係者ユーザのみ、暗号化することが目的なので、サーバ証明書を自己署名する
* 証明書作成にはいろんな方法があるみたいだが、apacheに組み込む前提でopensslコマンドを使ってサーバ上で作業する
```

# Problem

```
■自己署名証明書と独自認証局署名証明書
* 認証局が署名した証明書（有料）を使わずにSSL通信をおこなうためには、以下の２パターンがある
  1. 自己署名した証明書を作成する
  2. 独自に作成した認証局により署名したサーバ証明書を作成する
* 1の自己署名した証明書はアプリケーションによっては受け入れないものもあるらしい

■SSL３機能のうち自己署名で担保される機能
* SSLの３機能のうち、この手順の方法だと1の暗号化のみが可能
  1. 暗号化 ○
  2. 認証 △
  3. 改竄検出 △
```

# Preparation

```
$> uname -a
Linux *** 2.6.32-431.3.1.el6.x86_64 #1 SMP Fri Jan 3 21:39:27 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

$> cat /etc/issue
CentOS release 6.5 (Final)
Kernel \r on an \m

$> openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

$> /usr/local/apache/bin/apachectl -V | head -n 1
Server version: Apache/2.4.7 (Unix)

$> cat /usr/local/apache/build/config.nice
    #! /bin/sh
    #
    # Created by configure
    
    "./configure" \
    "--prefix=/usr/local/apache-2.4.7" \
    "--enable-mpms-shared=all" \
    "--enable-mods-shared=all" \
    "--enable-ssl" \
    "--enable-proxy" \
    "--enable-cache" \
    "--enable-mem-cache" \
    "--enable-rewrite" \
    "--with-included-apr" \
    "$@"

※ Apacheは--enable-sslをつけてインストールされている必要がある
```

# Manual

## SSL鍵配置ディレクトリを作成

```bash
## root user

## 
## Apache以下にsslディレクトリを作成し、ここにSSL通信で必要な証明書・鍵を置く
## 
cd /usr/local/apache/
mkdir -p ssl/{work,key,cert}
  # /usr/local/apache/
  #            |- ssl
  #               |- cert
  #               |- key (rootユーザのみ閲覧可能にする)
  #               |- work
chmod 700 ssl/key

## 
## Domain名をshell変数にいれておく
## 
DOMAIN_NAME='example.com'
echo $DOMAIN_NAME
```

## 乱数生成

```bash
## 
## 鍵を作成するための乱数を生成する
## 

cd /usr/local/apache/ssl

RAND_VALUE=`vmstat | tail -n 1`
echo $RAND_VALUE
  # vmstat（サーバリソースの統計情報）を取得してランダムに近い数値を取得する

echo $RAND_VALUE | openssl md5 > work/${DOMAIN_NAME}.rand
  # opensslコマンドでmd5ハッシュを生成して、ファイルに保存
  # openssl md5コマンドで得られるハッシュはmd5sumの結果と同一
  # -----
  # ※ Linuxには、/dev/urandomという乱数生成器があるという指摘いただきました。
  #   以下のようなコマンドで乱数生成するサンプルを見つけたので、メモしておきます。
  #   ただ、この生成方法で続きの手順が完了できるかは確認しきれていないです。
  #   dd if=/dev/urandom of=work/${DOMAIN_NAME}.rand count=1024 bs=1024
chmod 700 work/${DOMAIN_NAME}.rand
```

## 秘密鍵生成

```bash
## 
## openssl genrsaコマンドでRSA形式の秘密鍵を生成
## 擬似乱数を渡して、2048bitで暗号化している
## 
cd /usr/local/apache/ssl
openssl genrsa -rand work/${DOMAIN_NAME}.rand -des3 2048 > key/${DOMAIN_NAME}_key.pem
  # 秘密鍵のパスフレーズを入力

ls -l key/${DOMAIN_NAME}_key.pem
chmod 700 key/${DOMAIN_NAME}_key.pem
```

## CSR生成

```bash
##
## CSRとは、サーバ証明書への署名を認証局へ要求するための申請書のようなもの
## Certificate Signing Request
## CSR作成時に、コモンネーム（https通信したいドメイン名）や運営者情報などの入力を促される
## （各認証局に署名を依頼する場合、email, passwordなどの入力はemptyのままにしておくよう注意書きしている認証局が多い）
## CSRはここで入力した情報に加えて、さっき作った秘密鍵と対になる公開鍵情報も含まれている
## 
cd /usr/local/apache/ssl
openssl req -new -key key/${DOMAIN_NAME}_key.pem -out work/${DOMAIN_NAME}_csr.pem
  # pass phraseは、先ほど設定した秘密鍵のパスを入力する
  # 秘密鍵から公開鍵を算出するため、秘密鍵を指定する必要がある
  # （秘密=>公開の特定は簡単、公開=>秘密の特定はほぼ不可能という暗号アルゴリズムの特性）
chmod 700 work/${DOMAIN_NAME}_csr.pem
```

## 証明書の生成

```
* ここまでの手順は自己署名も認証局署名も同じ
* CSRを認証機関に送信すれば正当なサーバ証明書に、CSRから自分で作成すれば自己署名証明書となる
```

### 自己署名

```bash
cd /usr/local/apache/ssl
openssl req -x509 -in work/${DOMAIN_NAME}_csr.pem -key key/${DOMAIN_NAME}_key.pem -out cert/${DOMAIN_NAME}_crt.self.pem -days 3650
  # 10年間有効な自己署名のサーバ証明書を作成
chmod 700 cert/${DOMAIN_NAME}_crt.self.pem
```

## Apache Setting

```
##
## 443ポートをApacheがListenするように追加
## すでに80ポートはListenしているはずなので、この下に追記する
## 
Listen 80
Listen 443

## 
## /usr/local/apache/conf/httpd.confのmod_sslが有効になっていなければ有効化
## 
LoadModule ssl_module modules/mod_ssl.so
```

```
## 
## VirtualHostディレクティブをSSLポートに変更
## 
<VirtualHost {サーバのIPアドレス}:443>

## 
## VirtualHost設定内に以下を記載
## 
   SSLEngine on
   SSLCertificateFile "/usr/local/apache/ssl/cert/{ドメイン名}_crt.pem"
   SSLCertificateKeyFile "/usr/local/apache/ssl/key/{ドメイン名}_key.pem"
```

```bash
## 
## SSLまわりの変更はapacheのstop/startが必須
## また、configtestで検出できない問題も多く、restartコマンドをうってもstopだけしてstartに失敗することもある
## すでに他のサービスが稼働しているサーバで作業する際は十分に注意
## 

/usr/local/apache/bin/apachectl configtest
  # config syntax check
/usr/local/apache/bin/apachectl stop
/usr/local/apache/bin/apachectl start
ps -ef | grep httpd
```

Apacheの起動時に秘密鍵のパスフレーズを入力要求されたくない場合は、以下の方法で回避できる
http://qiita.com/metheglin/items/1ca54472f97a72f8c9b2

## Check

```
netstat -an | grep "LISTEN "
  # サーバが443port Listenするようになったことを確認
/usr/local/apache/bin/httpd -S
  # 想定のドメインがIP address:443を認識していることを確認
```

# References

* http://blog.jnito.com/entry/2013/05/26/064803
* http://hp.vector.co.jp/authors/VA027031/orenosp/selfca.txt
* http://www.slogical.co.jp/tech/openssl_command.html