opensslでサーバ証明書とルート証明書を作成するスクリプト

#### CentOS8で/etc/pki以下が変わった

以前書いたCentOS7でオレオレ証明書を作成する記事(https://qiita.com/masahiro-aoike/items/dbf17fa03c5973ce9068) にいいねしてもらえてるのだけど、CentOS8で試そうとしたところ*/etc/pki/tls/misc/CA* が存在していないっぽい。いちいちファイルを編集して証明書を作成するのも面倒なので、シェルに引数としてパラメータを渡すだけでサーバ側にインストールする証明書とクライアント側にインストールする証明書を出力できるスクリプトを作ってみた。

サーバ証明書として通常の**サーバ証明書と秘密鍵のペア**だけでなく、wildfly用の**PKCS12形式**の証明書も同時に出力するようにしている。

---

#### シェル実行時に読み込ませるファイルの準備

- /etc/pki/tls/openssl.cnfからコピーしてきて、CA_defaultセクションのディレクトリ設定を変更 (CentOS7とCentOS8で若干内容は違っているが変更箇所は同じ)

``` openssl.cnf
...
[ CA_default ]
dir = ./    #/etc/pki/CA → ./に変更
...
```
- ルート証明書用の設定ファイルを新規作成

``` v3_ca.txt
basicConstraints = critical, CA:true
keyUsage = critical, cRLSign, keyCertSign
subjectKeyIdentifier=hash
```
- サーバ証明書用の設定ファイルを新規作成

``` v3_server.txt
[SAN]
basicConstraints = CA:false
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
authorityKeyIdentifier=keyid,issuer

subjectAltName=@alt_names
basicConstraints=CA:FALSE
[alt_names]
```
#### シェルスクリプト本体

```make_cert.sh
#!/bin/bash

if [ $# -lt 9 ]; then
  echo "usage : "
  echo "  make_cert.sh -n [Common Name] -p [password] -d [expire days] -c [Country Name] -s [State or Province Name] -l [Locality Name] -o [Organization Name] -u [Organizational Unit Name] -a [Subject Alternative Name] -a ..."
  echo "    Subject Alternative Name : DNS or IPaddress (ex: DNS.1=localhost, IP.1=192.168.1.1)"
  exit 1;
fi

while getopts n:p:d:c:s:l:o:u:a: OPT
do
  case $OPT in
    "p" ) password=$OPTARG ;;
    "d" ) days="$OPTARG" ;;
    "c" ) subj+="/C="; subj+="$OPTARG" ;;
    "s" ) subj+="/ST="; subj+="$OPTARG" ;;
    "l" ) subj+="/L="; subj+="$OPTARG" ;;
    "o" ) subj+="/O="; subj+="$OPTARG" ;;
    "u" ) subj+="/OU="; subj+="$OPTARG" ;;
    "n" ) commonName="$OPTARG"; subj+="/CN="; subj+="$OPTARG" ;;
    "a" ) echo "$OPTARG" >> subjectAltName ;;
  esac
done

mkdir $commonName
touch index.txt
echo 01 > ./serial
cat v3_server.txt subjectAltName > $commonName/v3_server.txt

openssl genrsa -aes256 -passout pass:$password -out $commonName/cakey.pem 2048

openssl req -passin pass:$password -new -key $commonName/cakey.pem -out $commonName/cacert.csr -config openssl.cnf -subj $subj

openssl ca -passin pass:$password -in $commonName/cacert.csr -selfsign -keyfile $commonName/cakey.pem -notext -config openssl.cnf -subj $subj -outdir . -days $days -extfile v3_ca.txt -out $commonName/cacert.pem -batch

openssl x509 -in $commonName/cacert.pem -out $commonName/cacert.crt

rm index.txt
touch index.txt

openssl genrsa -aes256 -passout pass:$password -out $commonName/server.key 2048

openssl req -passin pass:$password -new -key $commonName/server.key -out $commonName/server.csr  -config openssl.cnf -subj $subj

openssl ca -passin pass:$password -in $commonName/server.csr -keyfile $commonName/cakey.pem -cert $commonName/cacert.pem -outdir . -notext -config openssl.cnf -extfile $commonName/v3_server.txt -extensions SAN -out $commonName/server.crt -days $days -batch

openssl rsa -passin pass:$password -in $commonName/server.key -out $commonName/server.key

openssl pkcs12 -passout pass:$password -export -in $commonName/server.crt -inkey $commonName/server.key -out $commonName/server.p12 -name server -CAfile ca.crt -caname server

rm -f serial* index.txt* *.pem subjectAltName
```

#### 使い方

引数無しで実行した際に表示されるように証明書を作成する際にプロンプト入力するパラメータを引数に与えて実行すると、実行ディレクトリ配下に*Common Name*で指定した名前のサブディレクトリが作成され、その中に各種ファイルが作成される。

```
$ ./make_cert.sh -n 192.168.0.10 -p password -d 3650 -c US -s CA -l Anaheim -o AnaheimElectronics -u vonBraun -a IP.1=192.168.0.10
```

なおsubjectAltNameに複数のDNS名やIPアドレスを指定したい場合には、`-a IP.1=192.168.0.10 -a IP.2=192.168.0.11`のようにすれば良い。

出来上がるファイルは

- server.key ... サーバ秘密鍵
- server.crt ... サーバ証明書
- server.p12 ... wildflyで使うPKCS12形式の証明書
- cacert.crt ... クライアント側にインストールするルート証明書("信頼されたルート証明機関"などにインストール)


wildflyでのオレオレ証明書の設定については、また別途…。