openssl と keytool を使った keystore 作成スクリプトを解析する

TSLなし、TSLあり、TSL+Client 証明書という環境のテストをKafkaクライアントから実施したいと思っている。
多分Bitnami の helm チャートが一番簡単っぽいので、それでコンフィグレーション出来るようにしたい。

ところが、自分が十分に `openssl` や `keytool` をよくわかっていないことが分かったので、そのチュートリアルで使われている [スクリプト](https://raw.githubusercontent.com/confluentinc/confluent-platform-security-tools/master/kafka-generate-ssl.sh)で使われている `openssl` と `keytool` のコマンドを理解しながら何をやっているか整理したいと思う。

# 1. CA certificate と CA の Private Key の作成
詳細のオプションの説明は下に書いておいたが、CA の Private Key と、CA の自己署名証明書を作成している。作成時には証明書に下記の情報を入れる必要があり、最初に証明書のパスワードを聞かれるので入力している。`Common Name` は、通常は `Server FQDN` を入れるのだと思うが、自分の名前でもよさげなので、自己証明書なので、自分の名前を入れておく。

_Line 70_

```bash
$ openssl req -new -x509 -keyout ca-private-key -out ca.crt -days 1000
Generating a RSA private key
.....................+++++
..............................................+++++
writing new private key to 'ca-private-key'
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) [AU]:US
State or Province Name (full name) [Some-State]:Washington
Locality Name (eg, city) []:Kirkland
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Simplearchitect
Organizational Unit Name (eg, section) []:Main
Common Name (e.g. server FQDN or YOUR name) []:tsushi
Email Address []:MY_EMAIL_HERE
```

* `req`: サブコマンド。PKCS#10 の証明書リクエストと、証明書を作成するユーティリティ
* `-new`: 証明書のリクエストを作成する。`-key` が指定されていなければ、RSA の private keyを作成する。
* `-x509`: 証明書リクエストの代わりに、自己署名証明書(SelfSignedCertificate) を出力する
* `-keyout`: 新しく作られた private key を出力する
* `-out`: 標準出力をファイルに出力する。この場合、`-x509`の項目が指定されているので自己署名証明書が出力される
* `-days`: 出力される証明書の有効日数。デフォルトは30 日

NOTE: `man openssl req` より

## Output

```bash
$ ls
ca-private-key  ca.crt
``

# 2. Ca証明書　を trust keystore に格納
1. で作成した、CA用の 証明書を Keystore に入れる。`openssl` と `keytool` はやれることがオーバーラップしてややこしいが、`keytool` しかできないことに、KeyStoreの作成がある。KeyStore は証明書をエイリアスをつけて格納できたり、取り出せたりするキーストアだ。Java のエコシステムでよく使われる。Kafaも、Javaで作られているので、これを参照するのだと思う。ただ、他の言語がクライアントの場合は、KeyStoreを使わない場合が多いと思うので、理屈を知っておく必要がある。実行時に1.で聞かれたパスワードを聞かれる

_Line 92_

```bash
keytool -keystore kafka.truststore.jks -alias CARoot -import -file ca.crt 
```

* `-import`: サブコマンド `importcert`と同様。証明書か証明書チェーン (PKCS#7 reply か X.509証明書)を読み込んでキーストアに入れる。
* `-keystore`: キーストア。なければ作成される。
* `-alias`: ストアされるエンテイティ（証明書）のエイリアス
* `-file`: 読み込む証明書


## Output

新たにキーストアが作成されている。

```bash
$ ls
ca-private-key  ca.crt  kafka.truststore.jks
```

# 3. キーペアと、証明書の作成、キーストアへの格納

ここでいう証明書は、CA証明書にサインされる予定の証明書で、サーバーに格納されるなどの用途で使われる証明書です。

_Line 144_

```bash
keytool -keystore kafka.keystore.jks -alias localhost -validity 1000 -genkey -keyalg RSA
Enter keystore password:  
Re-enter new password: 
What is your first and last name?
  [Unknown]:  Tsuyoshi Ushio
What is the name of your organizational unit?
  [Unknown]:  Simplearchitect
What is the name of your organization?
  [Unknown]:  Main
What is the name of your City or Locality?
  [Unknown]:  Kirkland
What is the name of your State or Province?
  [Unknown]:  Washington
What is the two-letter country code for this unit?
  [Unknown]:  US
Is CN=Tsuyoshi Ushio, OU=Simplearchitect, O=Main, L=Kirkland, ST=Washington, C=US correct?
  [no]:  yes
```

* `-genkey`: サブコマンド。 `-genkeypair` と同様。Key Pair (Private/Public key) と、X.509 の自己証明書が、証明書チェーンとしてストアされる。
* `-validity`: 有効日数
* `-keyalg`: キーアルゴリズム名

## Output

```bash
$ ls
ca-private-key  ca.crt  kafka.keystore.jks  kafka.truststore.jks
```


# 4. キーストアから、CA証明書を取り出す

_Line 157_

```bash
$ keytool -keystore kafka.truststore.jks -export -alias CARoot -rfc -file ca.crt.exported
Enter keystore password:  
Certificate stored in file <ca.crt.exported>
```

KeyStoreから、出力されたCA証明書は同じものです。スペースが違うので、`-b`オプションをdiffに着けていいます。

```bash
$ls
ca-private-key  ca.crt  ca.crt.exported  kafka.keystore.jks  kafka.truststore.jks
$diff ca.crt ca.crt.exported -b
```

# 5. 証明書のサインリクエストを取得する

先ほど 3. で作成した自己証明書に対して、サインリクエストを作成します。

_Line 163_

```bash
$ keytool -keystore kafka.keystore.jks -alias localhost -certreq -file cert-sign-request
```

## Output

```bash
$ls
ca-private-key  ca.crt  ca.crt.exported  cert-sign-request  kafka.keystore.jks  kafka.truststore.jks
```

# 6. CA の Private Key で証明書にサインする

_Line 170_

```bash
$ openssl x509 -req -CA ca.crt -CAkey ca-private-key -in cert-sign-request -out signed.crt -days 1000 -CAcreateserial
Signature ok
subject=C = US, ST = Washington, L = Kirkland, O = Main, OU = Simplearchitect, CN = Tsuyoshi Ushio
Getting CA Private Key
Enter pass phrase for ca-private-key:
```

* `x509`: 証明書のサインと表示のためのユーティリティ
* `-out`: 標準出力から読み込みを行う
* `-CA`: CA 証明書を指定する
* `-CaKey`: CA の Private Key を指定する
* `-req`: デフォルトでは、標準入力から証明書を読み込むが、代わりにリクエストを読み込む
* `-CAcreateserial`: CAシリアルナンバーファイルが出力される（使用が推奨される）


## Output 

サインされた証明書が出力されている。また、CAのシリアルファイル `ca.srl` が出力されている。

```bash
ca-private-key  ca.crt  ca.crt.exported  ca.srl  cert-sign-request  kafka.keystore.jks  kafka.truststore.jks  signed.crt
```

# 7. CA 証明書をキーストアに入れる 

_Line 180_

```bash
$ keytool -keystore kafka.keystore.jks -alias CARoot -import -file ca.crt
```

スクリプトではこの後、CA証明書を消している。キーストアから取り出せるから

# 8. サインされた証明書をキーツールに格納する

_Line 188_

```bash
keytool -keystore kafka.keystore.jks -alias localhost -import -file signed.crt
```

# まとめ

スクリプトで一瞬で生成されて、`keystore` に明るくなかったので、どうしたらいいんだろう？と思っていましたが、全部解析してみると `keytool` と `openssl` のコマンドを背景含めて理解できました。

# Resource

下記のほかには、`man openssl <subcommand>` で検索すると良いマニュアルが出てきました。

* [keytool](https://docs.oracle.com/javase/7/docs/technotes/tools/solaris/keytool.html) 古いので古い名前が参照されている(e.g. -import)
* [keytool common options](https://docs.oracle.com/en/java/javase/14/docs/specs/man/keytool.html#commands-and-options)
* [A Java “keytool genkey” example](https://alvinalexander.com/java/java-using-keytool-genkey-private-key-keystore/)
* [openssl コマンドの使い方](https://qiita.com/hana_shin/items/6d9de0847a06d8ee95cc) かなり良い openssl の使い方
* [Java “keytool import”: How to import a certificate into a keystore file](https://alvinalexander.com/java/java-using-keytool-import-certificate-keystore/)