私的サーバー構築日誌：オレオレ認証局

# 能書き

[私的サーバー構築日誌：仕切り直し](https://qiita.com/katz_engineer/items/1f21de2bd9072c260ae6)からの自宅サーバー構築の続きです。

認証局の構築は[以前](https://qiita.com/katz_engineer/items/ada7b08e7c0254e39126)もやりまして、その焼き直しですが。そのまま再掲でも詰まらないので、関連コマンドをdockerコンテナの中に封じ込めてみます。

## 概要説明と参考文献

ものすご～く端的に言うと。

周知の通り、証明書はそれだけでは用を為しません。証明書が正しい事を証明する為に電子署名する機関が認証局であり、取り敢えず無条件で信用するのがルート認証局です。全ての署名はこのルート認証局の信用に依って成り立っています。

ルート認証局は、通常は社会的合意に基づいて信用されます。しかしコストなどの問題から私的用途の為にはルート認証局を自分で用意する事があります。これがプライベート認証局、通称オレオレ認証局です。

このような認証基盤の全貌をPKIと呼びます。

これについては下記文献に丁寧な説明があります。

参考文献：[認証局（CA）の役割　～PKI基礎②～ - マイクロソフ党ブログ](https://microsoftou.com/role-of-ca/)
参考文献：[電子メールのセキュリティ（5） ～ 認証局（CA）とPKI ～ - 基礎からわかる！パソコン入門・再入門](https://www.yamanjo.net/knowledge/internet/internet_20.html)

UbuntuにはデフォルトでOpenSSLがインストールされています。これでオレオレ認証局を作る事も出来ますが、手順が少々面倒臭い。 
例えば下記の記事が図解も入っていて分かり易い。しかしこの記事はCentOSなんですよね。残念。

参考文献：[OpenSSLでプライベート認証局の構築（ルートCA、中間CA） - Qiita](https://qiita.com/bashaway/items/ac5ece9618a613f37ce5)

Ubuntuの場合は下記が参考になりそうです。微妙に古くなりかけていますが。

参考文献：[Ubuntu 18.04 LTS で OpenSSL を使ったプライベート認証局＆証明書を作る - 未完放流](https://idwonder21.hatenablog.com/entry/2019/03/03/123510)

なお、OpenVPNプロジェクトの中でこの手間を軽減するツールが作られているようで、easy-rsaと呼ばれています。easy-rsaを用いた手順は、ちょっとぐぐればそこら中に解説記事があります。例えば下記など。

参考文献：[easy-rsaでプライベートCA(認証局)を作ってオレオレ証明書ではないローカル用TLS証明書の管理をする](https://r-o-head.tk/post/private-ca-with-easy-rsa/)
参考文献：[easy-rsa 3 で認証局を構築する - yamata::memo](https://yamatamemo.blogspot.com/2014/01/easy-rsa-3.html)

因みに、認証局なんて面倒臭い事をしないでドカンとオレオレ証明書を作っちまえ！と思ったら、少なくともKerberosではうまくいかないらしい。他にもダメな事例が散見されるようです。

参考文献：[KerberosのバックグラウンドにOpenLDAPを使う - Qiita](https://qiita.com/kanatatsu64/items/ec50707002c5dbd7330d#tls%E3%81%AE%E6%9C%89%E5%8A%B9%E5%8C%96)

そういう訳で、この記事ではeasy-rsaを使ってみます。

## 目標

- easy-rsaを使用してルート認証局を作る所までを実施します。
- Dockerコンテナを作り、一連のコマンド操作はその中で実施します。

# easy-rsaのコンテナを作成

## スナップショット

スナップショットだいじ。超だいじ。

```console
sudo zfs snapshot tank/root/ubuntu@$(date +%Y%m%d_%H%M%S)_before_easy-rsa
```

## 取り扱いユーザー作成

certというユーザーを作成し、ログイン禁止にして、証明書などはこれに扱わせます。

こういう時にどういうユーザーを作成するのがLinux的に一般的なのかわかりません。ログイン禁止という要請からパスワードを設定しないユーザーを作成してみました。

こういう場合の定石を御存知の方がいらっしゃいましたら御教示お願いします:bow_tone1:

```console
CA_USER=cert
```

```console
sudo zfs create -o com.ubuntu.zsys:bootfs-datasets=tank/root/ubuntu -o canmount=on -o mountpoint=/home/$CA_USER tank/userdata/$CA_USER
```

```console
sudo useradd -s /bin/bash $CA_USER
```

```console
sudo cp -a /etc/skel/. /home/$CA_USER
```

```console
sudo chown -R $CA_USER:$CA_USER /home/$CA_USER
```

```console
sudo usermod -aG docker $CA_USER
```

パスワードを設定していないのでsshログインできません。`su`コマンドでも一般ユーザーからcertになる事は出来ません。

```console
$ su $CA_USER
Password:
```

rootユーザーとしてcertになります。少々面倒ですが。まあ、普段は滅多にやらない操作なので我慢します。セキュリティとはそういう物でしょう。たぶん。

```console
$ sudo su $CA_USER
$ whoami
cert
$ exit
exit
```

`/etc`を確認。

```console
sudo svn di --diff-cmd diff -x -U0 /etc
```

こうなりました。

```console
$ sudo svn di --diff-cmd diff -x -U0 /etc
Index: /etc/group
===================================================================
--- /etc/group  (revision 13)
+++ /etc/group  (working copy)
@@ -60 +60,2 @@
-docker:x:999:admin
+docker:x:999:admin,cert
+cert:x:1001:
Index: /etc/gshadow
===================================================================
--- /etc/gshadow        (revision 13)
+++ /etc/gshadow        (working copy)
@@ -60 +60,2 @@
-docker:!::admin
+docker:!::admin,cert
+cert:!::
Index: /etc/passwd
===================================================================
--- /etc/passwd (revision 11)
+++ /etc/passwd (working copy)
@@ -32,0 +33 @@
+cert:x:1001:1001::/home/cert:/bin/bash
Index: /etc/shadow
===================================================================
--- /etc/shadow (revision 11)
+++ /etc/shadow (working copy)
@@ -32,0 +33 @@
+cert:!:19596:0:99999:7:::
Index: /etc/subgid
===================================================================
--- /etc/subgid (revision 10)
+++ /etc/subgid (working copy)
@@ -1,0 +2 @@
+cert:165536:65536
Index: /etc/subuid
===================================================================
--- /etc/subuid (revision 10)
+++ /etc/subuid (working copy)
@@ -1,0 +2 @@
+cert:165536:65536
Index: /etc/zfs/zfs-list.cache/tank
===================================================================
--- /etc/zfs/zfs-list.cache/tank        (revision 12)
+++ /etc/zfs/zfs-list.cache/tank        (working copy)
@@ -6,0 +7 @@
+tank/userdata/cert     /home/cert      on      on      on      on      on      off     on      off     -       none    -       -       -       -       -      -                           --
```

コミットします。

```console
sudo svn ci -m"user $CA_USER" /etc
```

## コンテナ作成

まずはcertユーザーになります。

```console
sudo su $CA_USER
```

認証局の名前は、今回は`demoCA`とします。

```console
CA_NAME=demoCA
```

```console
cd
mkdir $CA_NAME
```

`docker-compose.yml`ファイルはこうなります。

```console
cat <<___ >docker-compose.yml
version: '3.8'
services:
  ca:
    build: .
    volumes:
      - .:/mnt
    tty: true
___
```

そして`Dockerfile`です。

```console
cat <<___ >Dockerfile
FROM ubuntu:22.04
RUN groupadd -g $(id -g) $USER \
 && useradd -u $(id -u) -g $(id -g) -s /bin/bash $USER \
 && apt update \
 && apt upgrade -y \
 && apt install -y easy-rsa
___
```

このDockerfileだと、必要なインストールは起動した時に完了します。

```console
docker compose up -d
```

dockerコンテナ内でcertユーザーになれる事を確認します。

```console
docker compose exec -e CA_USER=$USER ca /bin/bash
```

```console:コンテナ内
su $CA_USER
whoami
exit
exit
```

# easy-rsaを利用したルート認証局の作成

## Dockerコンテナに入る

コンテナに入り、certユーザーになります。

```console
cd
cd $CA_NAME
docker compose exec -e CA_USER=$USER -e CA_NAME=$CA_NAME ca /bin/bash
```

```console:コンテナ内
su $CA_USER
```

##  公開鍵インフラストラクチャ(PKI)ディレクトリの準備

```console:コンテナ内
cd /mnt/$CA_NAME
ln -s /usr/share/easy-rsa/* .
./easyrsa init-pki
```

## 認証局(CA)の作成

まずは所定のディレクトリに`var`ファイルを作成します。

`/opt/demoCA/vars.example`というファイルがあるのでこれを編集すれば良さそうですが、ここでは下記のように新規作成します。それぞれの値は自分の状況に応じて修正して下さい。忘れた頃に騒ぎになるのが嫌なので、私は百年認証局にしました。

```console
cat <<___ >pki/vars
set_var EASYRSA_ALGO      "ec"
set_var EASYRSA_DIGEST    "sha512"
set_var EASYRSA_CA_EXPIRE 36524
___
```

次に、認証局のルート公開鍵と秘密鍵のペアを作成します。

下記コマンドを実行すると、キーペアのパスフレーズを入力するように求められます。必ず強力なパスフレーズを入力し、安全な場所に書き留めます。

更に、CAの共通名(CN; Common Name)を確認するように求められます。CNは、認証局のコンテキストでこのマシンを参照するために使用される名前です。任意の文字列を入力できますが、インターネット上で使う予定があれば自分の所有しているドメインにするのが良いでしょう。今回はLAN内のDNSサーバで管理しているマシン名にします。

```console
./easyrsa build-ca
```

`.rnd`ファイルを開けないエラーが発生する事がありますが、今回は特に問題無いようです。万が一そのようなエラーが発生したら、[以前の記事](https://qiita.com/katz_engineer/items/ada7b08e7c0254e39126#%E8%AA%8D%E8%A8%BC%E5%B1%80ca%E3%81%AE%E4%BD%9C%E6%88%90)を参照ください。

パスフレーズとCNを入力して成功すると、下記の2ファイルが生成されます。

- CAの公開鍵 `/mnt/demoCA/pki/ca.crt`
- CAの秘密鍵 `/mnt/demoCA/pki/private/ca.key`

秘密鍵は絶対に漏らしてはいけない物になります。

## 内容確認

作った認証局の内容を確認します。

参考文献：[opensslコマンドでサーバーにアクセスして確認する - opensslコマンドを使ったSSL証明書の確認方法 - やさしいopensslコマンドによるSSL証明書の確認方法 - Oji-Cloud](https://oji-cloud.net/2020/07/15/post-5114/)
参考文献：[証明書の期限確認 - 発行されたSSL証明書の内容 - SSL証明書の内容をopensslで確認する](https://qiita.com/m-chika/items/e4936feb4087b7ddbe8b#%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E6%9C%9F%E9%99%90%E7%A2%BA%E8%AA%8D)

```console:コンテナ内
cd /mnt/$CA_NAME/pki
openssl x509 -text -in ca.crt | grep -E "Issuer:|Subject:"
openssl x509 -dates -noout -in ca.crt
```

下記の実行例は、作成時にCN(Common Name)として`demoCA`を指定した場合の結果です。

```console:コンテナ内
$ cd /mnt/$CA_NAME/pki
$ openssl x509 -text -in ca.crt | grep -E "Issuer:|Subject:"
        Issuer: CN = demoCA
        Subject: CN = demoCA
$ openssl x509 -dates -noout -in ca.crt
notBefore=Aug 20 07:52:32 2023 GMT
notAfter=Aug 20 07:52:32 2123 GMT
```

ホストマシンでも確認できます。

まずはコンテナを抜けます。

```console:コンテナ内
exit
exit
```

それから確認。

```console
cd
cd $CA_NAME/pki
```

```console
openssl x509 -text -in ca.crt | grep -E "Issuer:|Subject:"
openssl x509 -dates -noout -in ca.crt
```

Dockerコンテナ内での確認と同じ結果を得られます。

```console
$ openssl x509 -text -in ca.crt | grep -E "Issuer:|Subject:"
        Issuer: CN = demoCA
        Subject: CN = demoCA
$ openssl x509 -dates -noout -in ca.crt
notBefore=Aug 20 07:52:32 2023 GMT
notAfter=Aug 20 07:52:32 2123 GMT
```

最後に。certユーザーから抜けて終わりです。

```console
exit
```

# 仕舞い

ルート認証局、通称オレオレ認証局を作成しました。役に立つのは証明書を作成した時になりますが、その作成手順はまた後日にします。

利用するマシン全部にインポートが必要なのでちょっと面倒ですが、自分だけの証明書を無料で設定する準備が出来ました。