お勉強環境の WEBサーバーで httpsを使いたい時、WEBブラウザでサーバー証明の注意が出るのを回避します。
サーバーのお勉強をしていると、WEBサーバーで httpsを使いたいことが多々あります。
特に昨今の WEBブラウザはセキュリティ対策を厳しくしてきていますので、httpsかつサーバー証明書も正当なものじゃないと面倒だったりします。
インターネットに公開しているサーバーであれば Let's Encriptでフリーのサーバー証明書を取るのですが、自宅LANに作っているテストサーバーではドメインもありませんのでこれは使えません。
そこで自宅LANにプライベート認証局を作って、テスト用サーバーの証明をしてあげようというのがここでの試みです。
本物の認証局は国(日本はデジタル庁らしい)などの厳格な審査を通っている会社で、サーバー証明書に付随させる署名を売っています。
例えば、私はお客さんの依頼で DegiCertって所から買った事があります。
手続きの過程で、この会社(デジサート・ジャパン合同会社だと思います)から、お客さんの所に電話で「あなたは○○社の△△様ですよね?」って確認の問い合わせがあったようです。
そんな手続きを踏んで、
- いかがわしくない人が運営しているサーバーである
- それを担保する署名人もいかがわしくない
と明らかになっています。
関係性はよくこんな図で説明されています。
httpsの通信では、WEBサーバーから「ここの認証局に署名してもらいました」というデータが届くのですが、この際に③で貰った認証局の証明書と突合させてその正当性を確認します。
でもこれまでインターネットで散々 httpsを使って通信していますが、認証局の証明書なんて貰った覚えはありません。
なので以前私は https通信時に認証局にも通信していると誤認していました。
実際の通信における登場人物はこの二者のみです。
どうりで認証局の証明書を貰った覚えがないはずです。
WEBブラウザに予め入っているのですから。
これは Firefoxの例です。
[設定]メニューから [プライバシーとセキュリティ]を選ぶと [証明書]って段落があります。
そこの証明書を表示…を押します。
[認証局証明書]タブに予め入っている証明書が羅列されます。
上に出てきた DigiCertがあることも分かります。
こうして有名な認証局(そもそも数が多くない)の証明書は WEBブラウザと一緒に入っているので、我々は特に気にせず上の仕組みを利用できるのでした。
さて、翻って本物の認証局を使わずに、家庭内LANで同じ仕組みを実現する(プライベート認証局と言います)にはどうするかなんですが、実は本物の認証局がやってる上の図の②を自分でやるのです。
そして肝は、③が手動になることです。
③が手動になるということは、使用する WEBブラウザ毎に手作業をしなければなりません。
家庭内LANではやり切れますが、小さな企業でも難しいと思います。
これが企業内LANでプライベート認証局が使われない理由の一つかと思います。
ここの実験では、上の図の関係を2つの OS環境で実現することにします。
現実の環境を考えると本来は認証局と WEBブラウザを動かすクライアントPCは別にするべきなんでしょうが、認証局って署名のデータを作る作業場であって OSとして独立していなければいけない訳でない概念的なものですので。
ここからの記述は便宜上以下とします。
Lubuntu 22.04(マシン名は Lubuntu2204) → Lubuntu
Ubuntu Server 22.04.2(マシン名は UbuntuServer2204-1) → Ubuntu Server
プライベート認証局 → 認証局
では、具体的にやってみます。
1.プライベート認証局を作る
Lubuntuでの作業になります。
ブログ等では認証局を「作る」「立てる」とかいう言葉で説明されることが多くて私は混乱しました。
読み進めるうち難しい観念を露わにしないように言葉を選んでいることは分かりましたが、中々に難解です。
結局のところ具体的には以下2つのことをしているだけです。
- 自分で作った暗号で自分のサーバーの証明をする(いわゆる俺俺証明書)
- 外部サーバーからの「署名してね」の依頼に対し署名をする
本物の認証局も根本的にはこれと同じ事をしていて「本物の認証局が信用できるって誰が担保してんの?」という疑問が湧きますが、国家等が担保しているって偉い人が書いていました。
(詳しくは知りません)
認証局のデータを作るにあたり、Lubuntu・Ubuntu Serverともに open-sslのセットと思われる [/usr/lib/ssl/misc/CA.pl]ファイルという open-sslを簡単に使うための Perlスクリプトがあります。
Canonicalが出してる Ubuntu用のマニュアルはこちら。
CA.pl
これを使うと認証局としてのデータを管理するディレクトリ階層とファイル作成を自動で作ってくれます。
open-sslを使う限りこのディレクトリ階層で管理をした方が汎用性があると思われます。
認証局を作るブログ記事を見ていると、多くの人が [root]ユーザーで作業していますが、必須ではなさそうなのであえて一般ユーザーの [subro] でやってみました。
ユーザーに合わせて、デフォルトの [/etc/ssl]ディレクトリの代わりに [/home/subro/work/ssl]ディレクトリを作業場所としています。
subro@Lubuntu2204:~/work/ssl$ /usr/lib/ssl/misc/CA.pl -newca
CA certificate filename (or enter to create)Enterを押す
Making CA certificate ...
====
秘密鍵ファイルを作る & SSLサーバ証明申請(CSR)ファイルを作る
openssl req -new -keyout ./demoCA/private/cakey.pem -out ./demoCA/careq.pem
..+...++++++++++++++++++++++++++++++++++++ 〜〜〜 長いので省略 〜〜〜
Enter PEM pass phrase:秘密鍵ファイルの新規パスワードを設定
Verifying - Enter PEM pass phrase:パスワードをもう一回
多分この時点で秘密鍵ファイルが demoCA/private/cakey.pem としてできている
-----
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.
-----
認証局(Lubuntu)のSSLサーバ証明申請(CSR)ファイルに埋め込む情報です。
適当に入れていますが、[Common Name]だけは何か入ってないとダメでした。
Country Name (2 letter code) [AU]:JA
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Chiyoda-ku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Subro Inc.
Organizational Unit Name (eg, section) []:Management
Common Name (e.g. server FQDN or YOUR name) []:Lubuntu2204
Email Address []:空にしました
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:空にしました
An optional company name []:空にしました
==> 0
====
====
上のSSLサーバ証明申請(CSR)に対して、上で作った秘密鍵ファイルを使って証明(署名)。
ここら辺が俺俺。
openssl ca -create_serial -out ./demoCA/cacert.pem -days 1095 -batch -keyfile ./demoCA/private/cakey.pem -selfsign -extensions v3_ca -infiles ./demoCA/careq.pem
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:上で設定した秘密鍵ファイルのパスワードを入れる
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number:
72:0d:75:0a:2c:57:95:46:91:ff:37:e6:67:6e:56:a0:31:05:18:61
Validity
Not Before: Apr 17 06:52:56 2023 GMT
Not After : Apr 16 06:52:56 2026 GMT
Subject:
countryName = JA
stateOrProvinceName = Tokyo
organizationName = Subro Inc.
organizationalUnitName = Management
commonName = Lubuntu2204
X509v3 extensions:
X509v3 Subject Key Identifier:
8B:D6:C9:48:68:6A:EC:F2:BF:C5:07:F9:89:F9:0D:B0:94:0D:AC:FE
X509v3 Authority Key Identifier:
8B:D6:C9:48:68:6A:EC:F2:BF:C5:07:F9:89:F9:0D:B0:94:0D:AC:FE
X509v3 Basic Constraints: critical
CA:TRUE
Certificate is to be certified until Apr 16 06:52:56 2026 GMT (1095 days)
Write out database with 1 new entries
Data Base Updated
==> 0
====
CA certificate is in ./demoCA/cacert.pem
できました。
結果このようなものが。
subro@Lubuntu2204:~/work/ssl$ tree
.
└── demoCA
├── cacert.pem 自分で署名した(俺俺)自分のサーバー証明書
├── careq.pem このサーバーのSSLサーバ証明申請(CSR)
├── certs
├── crl
├── crlnumber
├── index.txt 証明局として証明した履歴のデータベース
├── index.txt.attr
├── index.txt.old
├── newcerts
│ └── 720D750A2C57954691FF37E6676E56A031051861.pem cacert.pemと同じもの。署名したものの履歴と思われる。
├── private
│ └── cakey.pem このサーバーの秘密鍵
└── serial
[demoCA] というディレクトリ名はマニュアルを読む限り固定のようでした。
この名前は変えてしまっても良いようです。
[index.txt]ファイルが簡易データベースらしいので中を見てみました。
subro@Lubuntu2204:~/work/ssl$ cat index.txt
V 260416065256Z 720D750A2C57954691FF37E6676E56A031051861 unknown /C=JA/ST=Tokyo/O=Subro Inc./OU=Management/CN=Lubuntu2204
何となく…分かるような分からないような。
2.サーバー証明書の証明(署名)依頼を出す
Ubuntu Server(WEBサーバー)での作業です。
こちらではこの OS環境に対して 1回作業すれば良いので、[root]ユーザーでやっています。
ファイルの配置場所もデフォルトの [/etc/ssl]ディレクトリにしています。
subro@UbuntuServer2204-1:/etc/ssl$ sudo /usr/lib/ssl/misc/CA.pl -newreq
Use of uninitialized value $1 in concatenation (.) or string at /usr/lib/ssl/misc/CA.pl line 145.
====
Ubuntu Serverの秘密鍵を作る & このサーバーのSSLサーバ証明申請(CSR)を作る
openssl req -new -keyout newkey.pem -out newreq.pem -days 365
Ignoring -days without -x509; not generating a certificate
..+..+............+......++++++++++++ 〜〜〜 長いので省略 〜〜〜
Enter PEM pass phrase:Ubuntu Serverの秘密鍵の新規パスワードを入れる
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.
-----
このサーバーのSSLサーバ証明申請(CSR)に埋め込む情報です。本当はちゃんと入れないとダメなところ。
家庭内LAN用だから適当に入れていますが、Common Nameだけは実体に沿ったものにしないといけません。
もしこの WEBサーバーに https://ubuntuserver2204-1/ とアクセスするなら、「ubuntuserver2204-1」とします。
Country Name (2 letter code) [AU]:JA
State or Province Name (full name) [Some-State]:Tokyo
Locality Name (eg, city) []:Minato-ku
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Subro WebService Ltd.
Organizational Unit Name (eg, section) []:Web Developer
Common Name (e.g. server FQDN or YOUR name) []:ubuntuserver2204-1 ←ここが重要
Email Address []:空にしました
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:空にしました
An optional company name []:空にしました
==> 0
====
Request is in newreq.pem, private key is in newkey.pem
できました。
このようなものが。
subro@UbuntuServer2204-1:/etc/ssl$ ls -l
合計 40
drwxr-xr-x 3 root root 12288 3月 10 19:28 certs
-rw------- 1 root root 1854 4月 17 21:25 newkey.pem Ubuntu Serverの秘密鍵
-rw-r--r-- 1 root root 1045 4月 17 21:26 newreq.pem Ubuntu Serverの SSLサーバ証明申請(CSR)
-rw-r--r-- 1 root root 12419 2月 7 02:57 openssl.cnf
drwx--x--- 2 root ssl-cert 4096 4月 17 21:25 private
subro@UbuntuServer2204-1:/etc/ssl$ sudo ls -l private
合計 4
-rw-r----- 1 root ssl-cert 1704 3月 10 19:10 ssl-cert-snakeoil.key
このうち [newkey.pem]ファイルの内容は外に漏れるとマズいので、[private]ディレクトリの下(rootしか見ることができない)に移動しつつ名前も [private.pem] と変更しました。
subro@UbuntuServer2204-1:/etc/ssl$ sudo mv newkey.pem ./private/private.pem
subro@UbuntuServer2204-1:/etc/ssl$ sudo ls -l private
合計 8
-rw------- 1 root root 1854 4月 17 21:25 private.pem
-rw-r----- 1 root ssl-cert 1704 3月 10 19:10 ssl-cert-snakeoil.key
移動とファイル名変更ができました。
[ssl-cert]グループのメンバがこのファイルを利用できるよう、[private.pem]ファイルのグループとパーミッションも変更します。
(後で NGINXがこのファイルを読めるようにするため)
subro@UbuntuServer2204-1:/etc/ssl$ sudo chgrp ssl-cert ./private/private.pem
subro@UbuntuServer2204-1:/etc/ssl$ sudo chmod 640 ./private/private.pem
subro@UbuntuServer2204-1:/etc/ssl$ sudo ls -l private
合計 8
-rw-r----- 1 root ssl-cert 1854 4月 17 16:07 private.pem
-rw-r----- 1 root ssl-cert 1704 3月 10 19:10 ssl-cert-snakeoil.key
3.プライベート認証局で署名してもらう
Lubuntuでの作業になります。
Ubuntu Serverにできた SSLサーバ証明申請(CSR)である [newreq.pem]ファイルをどのような方法でも良いので Lubuntuに持っていきます。
私は scpで持っていきました。
この通り Lubuntuの認証局のディレクトリ [/home/subro/work/ssl] に持ってきました。
subro@Lubuntu2204:~/work/ssl$ ls -l
total 8
drwxrwxr-x 6 subro subro 4096 4月 17 16:33 demoCA
-rw-r--r-- 1 subro subro 1045 4月 17 21:42 newreq.pem
新しい WEBブラウザ相手ですと、SANs(Subject Alternative Names)というのを設定しておかないと正しい証明書とみなされないようなので、これの対応をします。
まず任意の名前のファイル(ここでは [sans.ext] としました)を作り、以下の内容を書きます。
subro@Lubuntu2204:~/work/ssl$ cat sans.ext
subjectAltName=DNS:ubuntuserver2204-1
それから CA.plを経て open-sslにこのファイルを読ませるオプションを渡すため、[OPENSSL_CONFIG]環境変数を設定します。
subro@Lubuntu2204:~/work/ssl$ export OPENSSL_CONFIG="-extfile sans.ext"
署名します。
CA.pl ではカレントディレクトリにある [newreq.pem]ファイルをデフォルトで読むようになっています。
subro@Lubuntu2204:~/work/ssl$ /usr/lib/ssl/misc/CA.pl -sign
====
open-sslコマンドに[sans.ext]ファイルを読ませるオプションが渡っています
openssl ca -extfile sans.ext -policy policy_anything -out newcert.pem -infiles newreq.pem
Using configuration from /usr/lib/ssl/openssl.cnf
Enter pass phrase for ./demoCA/private/cakey.pem:認証局の秘密鍵のパスワードを入れる
Check that the request matches the signature
Signature ok
Certificate Details:
Serial Number:
72:0d:75:0a:2c:57:95:46:91:ff:37:e6:67:6e:56:a0:31:05:18:65
Validity
Not Before: Apr 17 14:01:59 2023 GMT
Not After : Apr 16 14:01:59 2024 GMT
Subject:
countryName = JA
stateOrProvinceName = Tokyo
localityName = Minato-ku
organizationName = Subro SebService Ltd.
organizationalUnitName = Web Developer
commonName = ubuntuserver2204-1
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:ubuntuserver2204-1
Certificate is to be certified until Apr 16 14:01:59 2024 GMT (365 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
==> 0
====
Signed certificate is in newcert.pem
できました。
署名つきのサーバー証明書である [newcert.pem]ファイルができています。
subro@Lubuntu2204:~/work/ssl$ ls -l
total 20
drwxrwxr-x 6 subro subro 4096 4月 17 23:02 demoCA
-rw-rw-r-- 1 subro subro 4546 4月 17 23:02 newcert.pem
-rw-r--r-- 1 subro subro 1045 4月 17 21:42 newreq.pem
-rw-rw-r-- 1 subro subro 38 4月 17 22:41 sans.ext
サーバー証明した履歴のデータベースファイルはこのようになっていました。
subro@Lubuntu2204:~/work/ssl$ cat ./demoCA/index.txt
V 260416065256Z 720D750A2C57954691FF37E6676E56A031051861 unknown /C=JA/ST=Tokyo/O=Subro Inc./OU=Management/CN=Lubuntu2204
V 240416140159Z 720D750A2C57954691FF37E6676E56A031051865 unknown /C=JA/ST=Tokyo/L=Minato-ku/O=Subro SebService Ltd./OU=Web Developer/CN=ubuntuserver2204-1
この [newcert.pem]ファイルをどうにかして Ubuntu Serverに持っていきます。
私はscp(以下略)
Ubuntu Serverでは今回作ったものと分かるよう、新規作成した [/etc/ssl/ubuntuserver2204-1]ディレクトリに入れ、オーナー・グループ・パーミッションを秘密鍵と同じにしました。
subro@UbuntuServer2204-1:/etc/ssl$ ls -l ubuntuserver2204-1
合計 8
-rw-r----- 1 root ssl-cert 4546 4月 17 23:04 newcert.pem
4.NGINXでサーバー証明書を使う
Ubuntu Serverでの作業になります。
NGINXが Ubuntu Serverで動いている前提です。
なお NGINXのインストールについては「NGiNXサーバーを作る」に書いております。
NGINXで SSLを有効にするため、手っ取り早く [/etc/nginx/sites-available/default] という設定ファイルをイジってしまいます。
server {
#listen 80 default_server; コメントアウト
#listen [::]:80 default_server; コメントアウト
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name _;
ssl on; SSL有効化
ssl_certificate /etc/ssl/ubuntuserver2204-1/newcert.pem; Lubuntuで署名してもらった Ubuntu Serverのサーバー証明書
ssl_certificate_key /etc/ssl/private/private.pem; Ubuntu Serverの秘密鍵
ssl_password_file /etc/nginx/ssl/ubuntuserver2204-1.password; Ubuntu Serverの秘密鍵のパスワードが書いてあるファイル
location / {
try_files $uri $uri/ =404;
}
}
Ubuntu Serverの秘密鍵 [/etc/ssl/private/private.pem]ファイルはパーミッションをかなりキツくしているので、NGINXのワーカープロセスを実行している [www-data]ユーザーから読めません。
先程 [ssl-sert]グループのメンバなら読めるようにしておいたので、このグループに [www-data]ユーザーを追加します。
[/etc/group]ファイルの [ssl-cert]グループの行を編集します。
ssl-cert:x:119:www-data
Ubuntu Serverの秘密鍵 [/etc/ssl/private/private.pem]ファイルはパスワード設定されていますので、利用時にパスワードを入れないと使うことができません。
NGINXでは当該パスワードを記載したファイルを作っておくことでこの作業を自動でやってくれます。
このために任意のファイルを作って、そこにパスワードをテキストで書いておきます。
ここでは [/etc/nginx/ssl/ubuntuserver2204-1.password]ファイルとしました。
大事なパスワードなのでこのファイルもまたオーナー・グループ・パーミッションをキツくしています。
subro@UbuntuServer2204-1:/etc/ssl$ ls -l /etc/nginx/ssl
合計 4
-rw-r----- 1 root ssl-cert 10 4月 17 23:27 ubuntuserver2204-1.password
NGINXを再起動します。
subro@UbuntuServer2204-1:/etc/ssl$ sudo systemctl restart nginx
試しに WEBブラウザでアクセスしてみます。
我が家では [https://UbuntuServer2204-1] です。
とりあず NGINXは httpsでのアクセスを受けてはいますが、サーバー証明書が信用できない状態です。
これは WEBブラウザに上で作ったプライベート認証局(Lubuntu)の証明書が無いからですね。
5.Firefoxにプライベート認証局の証明書を仕込む
Lubuntuでの作業になります。
現在の認証局のディレクトリ [/home/subro/work/ssl] の内容はこう。
subro@Lubuntu2204:~/work/ssl/demoCA$ ls -l
total 56
-rw-rw-r-- 1 subro subro 4421 4月 17 15:52 cacert.pem 認証局のサーバー証明書
-rw-rw-r-- 1 subro subro 1017 4月 17 15:52 careq.pem
drwxrwxr-x 2 subro subro 4096 4月 17 15:51 certs
drwxrwxr-x 2 subro subro 4096 4月 17 15:51 crl
-rw-rw-r-- 1 subro subro 3 4月 17 15:51 crlnumber
-rw-rw-r-- 1 subro subro 279 4月 17 23:02 index.txt
-rw-rw-r-- 1 subro subro 21 4月 17 23:02 index.txt.attr
-rw-rw-r-- 1 subro subro 21 4月 17 21:45 index.txt.attr.old
-rw-rw-r-- 1 subro subro 123 4月 17 23:01 index.txt.old
drwxrwxr-x 2 subro subro 4096 4月 17 23:02 newcerts
drwxrwxr-x 2 subro subro 4096 4月 17 15:51 private
-rw-rw-r-- 1 subro subro 41 4月 17 23:02 serial
-rw-rw-r-- 1 subro subro 41 4月 17 21:45 serial.old
Firefoxの [設定]メニューから [プライバシーとセキュリティ]を選ぶと [証明書]って段落があります。
そこの証明書を表示…を押します。
[認証局証明書]タブを開きインポートを押します。
ファイラーが出てくるので、[/home/subro/work/ssl/demoCA/cacert.pem]ファイルを指定しました。
[この認証局によるウェブサイトの識別を信頼する]にチェックし、OKを押します。
しますと証明書一覧に「Subro. Inc.」が現れました。ハハッ ワロス
それで改めてアクセスしてみましたら、この通り警告なしで NGINXの画面になりました。
赤いところをクリックするとこのような表示が出ました。
一応 Firefoxが最初から持っている証明書以外のものという区別はされているようです。
欲しい結果が得られました。
==========
かなり長くなってしまいました。
結構難しくて、実際ここまで完遂させるまでに結構ハマっています。
色々なブログやら公式のマニュアルやらを読んでどうにかここまできましたが、理解を難しくしていたのは「どこで其の作業をするのか?」という点がどうにもハッキリしていなかったことです。
1つの OS上でできはするんですが、ここの実験のように認証局・WEBサーバー・WEBブラウザを分離した場合、それぞれの作業が必須のものなのか同一の OS上でやっているからそうなのかの切り分けが中々できませんでした。
この実験を通してどうにか理解することができたのですが、まだまだ理解が浅いと感じましたね。
でもまぁとりあえずの目的は果たせて、今後のお勉強時に httpsを使えるようになったと思いますので、またここに各ネタを増やせそうです。
技術書典で出てる同人誌みたい。