拡張子がややこしくないですか?
SSL/TLSについての概要はこちらにまとめています。
■証明書作成の流れ(2パターン)
パターン1:外部CAに署名してもらう
パターン2:自前CAで署名する
■パターン1:外部CAに署名してもらう
CSRを作成して認証局(DigiCert / Let's Encryptなど)に提出し、署名済みのサーバ証明書を取得する方法。本番環境はこちらが基本。
① サーバ秘密鍵を作成
openssl genrsa -out server.key 2048
genrsa: RSA秘密鍵を生成
-out server.key: 出力先ファイルとしてserver.keyを指定(拡張子は.pemの場合もある)
2048: 鍵の長さを2048ビットに指定
参考:公開鍵抽出
秘密鍵が生成されるが、その中には対応する公開鍵の情報も含まれている。
keyとcertが一致しているかの確認や公開鍵のみ共有したい場合などで、公開鍵をエクスポートするには以下コマンド
openssl rsa -in server.key -pubout -out public-key.pem
rsa: RSAの秘密鍵や公開鍵の操作を行う
-in server.key: 入力ファイルとして秘密鍵を指定
-pubout: 公開鍵を出力するよう指定
-out public-key.pem: 公開鍵の出力先ファイルを指定
② CSRを作成
openssl req -new -key server.key -out server.csr
req: 証明書署名要求(CSR)を作成または処理する
-new: 新しいCSRまたは証明書を生成する.※ここでは-x509オプションがないため、CSRが作成される
-key server.key: CSR作成に使用する秘密鍵を指定
-out server.csr: 生成されたCSRの出力先ファイルを指定
③ 外部CAに提出
作成した server.csr を認証局に提出する。
審査後、CSRの内容に対して“署名する”ことでサーバ証明書が発行され、中間CA証明書と共に返却される。
server.crt
intermediate.crt(中間CA)
④ サーバ設定(例:Nginx)
クライアントは以下のようにチェーンを辿って信頼する。
サーバ証明書(server.crt)
↓
中間CA(intermediate.crt)
↓
ルートCA (クライアントのOSに最初から入ってる信頼の起点)
サーバ証明書(server.crt)だけでは信頼チェーンが成立しないため、中間CA証明書と連結したfullchain.pemを設定する必要がある。
cat server.crt intermediate.crt > fullchain.pem
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/certs/fullchain.pem; #クライアントに提示する証明書チェーン。 fullchain.pem = server.crt + intermediate.crt
ssl_certificate_key /etc/nginx/certs/server.key; #サーバ側だけが保持する秘密鍵
location / {
proxy_pass http://backend;
}
}
⑤ クライアント設定は不要
公開されているCAの証明書を利用する場合、クライアントとなるPCやサーバOSは基本的にあらかじめ信頼しているルートCAを持っている。
⇒ 送られてきたサーバ証明書が信頼しているCA一覧(rootCA)で署名されていることを検証することができるため、基本的にはクライアント側での設定は不要。
またCAについてもLet's Encrypt などでは certbot 等により自動更新する構成が一般的
■パターン2:自前CAで署名する
自分でCA(認証局)を作り、そのCAでサーバ証明書に署名する方法。クライアントにCA配布必要。
外部公開しない、内で閉じたシステムでよく使われている。
① CA(認証局)を作成
秘密鍵(CA用)
openssl genrsa -out rootCA.key 4096
genrsa: RSA秘密鍵を生成する
-out rootCA.key: 出力先ファイルを指定
4096: 鍵長(CAは強めにするのが一般的)
ルートCA証明書
openssl req -x509 -new -nodes \
-key rootCA.key \
-sha256 -days 3650 \
-out rootCA.pem
req: CSRまたは証明書を作成するコマンド
-x509: CSRではなく自己署名証明書を作成(=CAになる)
-new: 新規作成
-nodes: 秘密鍵をパスフレーズなしで扱う(自動処理向け)
-key rootCA.key: 使用する秘密鍵
-sha256: 署名アルゴリズム
-days 3650: 有効期限(約10年)
-out rootCA.pem: 出力ファイル
② サーバ秘密鍵を作成
パターン1と同じ
openssl genrsa -out server.key 2048
③ CSRを作成
パターン1と同じ
openssl req -new -key server.key -out server.csr
④ CAで署名してサーバ証明書を作成
openssl x509 -req \
-in server.csr \
-CA rootCA.pem \
-CAkey rootCA.key \
-CAcreateserial \
-out server.crt \
-days 365 \
-sha256 \
-extfile san.txt
x509: 証明書の生成・操作
-req: CSRを元に証明書を発行する
-in server.csr: 入力CSR
-CA rootCA.pem: 使用するCA証明書
-CAkey rootCA.key: CAの秘密鍵
-CAcreateserial: シリアル番号ファイルを自動生成
-out server.crt: 出力するサーバ証明書
-days 365: 有効期限
-sha256: 署名アルゴリズム
-extfile san.txt: 拡張設定(SAN)を読み込む
openssl x509 -text -in server.crt -noout
で証明書の情報を確認できる
⑤ SAN設定(重要)
subjectAltName = @alt_names
[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
👉 SANがないと以下エラーになる場合あり:
ERRO[2024-08-08 23:02:14] Failed verifying certificate: x509: certificate relies on legacy Common Name field, use SANs instead
ERRO[2024-08-08 23:02:14] An error occurred: x509: certificate relies on legacy Common Name field, use SANs instead
⑥ クライアント側にCAを配布
自己署名証明書や内部CAの証明書を使用している場合、クライアント側はoptionで作成されたルートCA証明書を信頼済みリストに登録することで、システム上のアプリケーションがその証明書を信頼できるようにする。
※配置場所や実装しているシステム(Apache,Nginx等)により異なるので注意
RHEL/Rocky/CoreOS系
# CA配置
cp my-root-ca.crt /etc/pki/ca-trust/source/anchors/
# 反映
update-ca-trust extract
# 信頼リスト確認
trust list
ファイルとしては、
/etc/pki/tls/certs/ または /etc/ssl/certs/ ディレクトリの
ca-bundle.crt または ca-bundle.trust.crt
等にリストされる。(色んなところにあるな…)
Ubuntu/Debian系
# CA配置
cp my-root-ca.crt /usr/local/share/ca-certificates/
# 反映
update-ca-certificates
これで、curl,docker,podmanなどのアクセス含めそのサイトを信頼するようになる
Windows
ちなみにwindowsPCやサーバでは基本的に以下の方法で追加できる。
`certmgr.msc` または `mmc`
「証明書(ローカルコンピューター)」追加
"信頼されたルート証明機関"にインポート
(非推奨)サーバで直接署名して作成する場合
④については、-signkeyで指定することで、CAで署名せずにサーバ自身の秘密鍵を使って署名することもできる
openssl x509 -req \
-days 365 \
-in server.csr \
-signkey server.key \ #サーバの秘密鍵
-out server.crt \
-extfile san.txt
CAが署名する場合は信頼されるが、自己署名になるため誰も信頼してない状態になる。
クライアント側からみてもそのCA信頼してる?→知らない、なのでエラーになるが、サーバ証明書をそのままCAとして登録することで対処は可能。
ただ、CAではrootCA.pem 1個配ればOKだが、この場合はサーバ証明書毎にひとつずつ登録することになるため、管理は煩雑になる
■作成例
ここでは上記非推奨の自己署名する場合の出力例
[root@host01 ~]# openssl genrsa -out private.key 2048 #秘密鍵作成
Generating RSA private key, 2048 bit long modulus
....................................+++
............................................................+++
e is 65537 (0x10001)
[root@host01 ~]#
[root@host01 ~]# ls
private.key
[root@host01 ~]#
[root@host01 ~]# cat private.key
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAv9bwNG3hA
(略)
dczV46uEYrM/oUur95a1KZRSh
-----END RSA PRIVATE KEY-----
[root@host01 ~]#
[root@host01 ~]# openssl req -new -key private.key -out server.csr #CSR作成
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) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:Raccoon City
Organization Name (eg, company) [Default Company Ltd]:Umbrella
Organizational Unit Name (eg, section) []:human experiment Unit
Common Name (eg, your name or your server's hostname) []:host01.local
Email Address []:hogehoge.co.jp
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
[root@host01 ~]#
[root@host01 ~]# ls
private.key server.csr
[root@host01 ~]# cat server.csr
-----BEGIN CERTIFICATE REQUEST-----
MIIC4zCCAcsCAQAwgZ0xCzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzEVMBMG
(略)
obc/VkE6A/q7OJa6u5efANIn8Tcj4L4=
-----END CERTIFICATE REQUEST-----
[root@host01 ~]#
[root@host01 ~]# vi san.txt
[root@host01 ~]# cat san.txt
subjectAltName = DNS:example.com
[root@host01 ~]#
[root@host01 ~]# openssl x509 -req -days 365 -in server.csr -signkey private.key -out server.crt -extfile san.txt #秘密鍵で署名してサーバ証明書作成
Signature ok
subject=/C=JP/ST=Tokyo/L=Raccoon City/O=Umbrella/OU=human experiment Unit/CN=host01.local/emailAddress=hogehoge.co.jp
Getting Private key
[root@host01 ~]#
[root@host01 ~]# ls
private.key san.txt server.crt server.csr
[root@host01 ~]#
[root@host01 ~]# cat server.crt
-----BEGIN CERTIFICATE-----
MIID2TCCAsGgAwIBAgIJAOy0I96HysgOMA0GCSqGSIb3DQEBCwUAMIGdMQswCQYD
(略)
gPh37FrGGL+hZnn8fSD2JlO4ENoDPkZhjP7Ywso=
-----END CERTIFICATE-----
[root@host01 ~]#
[root@host01 ~]# openssl x509 -text -in server.crt -noout #サーバ証明書確認
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
ec:b4:23:de:87:ca:c8:0e
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=JP, ST=Tokyo, L=Raccoon City, O=Umbrella, OU=human experiment Unit, CN=host01.local/emailAddress=hogehoge.co.jp
Validity
Not Before: Dec 4 14:31:37 2024 GMT
Not After : Dec 4 14:31:37 2025 GMT
Subject: C=JP, ST=Tokyo, L=Raccoon City, O=Umbrella, OU=human experiment Unit, CN=host01.local/emailAddress=hogehoge.co.jp
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:bf:d6:f0:34:6d:e1:01:c4:c6:ca:1e:e3:4e:5c:
1e:25:d1:52:eb:36:fb:bc:24:35:23:d9:a4:cd:4c:
ba:9d:6f:20:19:2c:4b:4c:11:2b:e8:6f:0f:80:8f:
aa:76:88:89:bc:1f:78:7f:a3:f8:f1:4a:01:1f:73:
71:52:aa:20:82:a1:38:93:ec:f6:cf:75:68:8f:ff:
ce:82:f6:4f:51:01:e3:bd:b6:b8:fc:98:9d:d0:80:
2f:29:3c:ac:54:ab:b1:c6:ee:5b:8f:f2:4d:0a:4a:
76:2b:cc:c1:9f:24:93:18:66:85:bb:3e:8b:80:b1:
d1:96:d9:3d:eb:dc:80:84:7d:71:d6:ef:c1:1e:cd:
6b:08:29:7c:6d:00:f9:51:ff:d8:8e:3b:77:26:0e:
66:ca:c9:17:c2:ff:a8:e3:1a:83:f8:24:24:4f:6a:
6f:0c:8d:71:e9:3d:c5:2f:80:4a:52:32:bf:dd:54:
2d:98:fd:47:21:09:51:59:07:36:13:2a:f0:e7:19:
ee:d1:39:f9:c3:d2:f6:bb:bc:d2:92:92:bc:10:27:
1c:6d:75:42:fc:68:50:f5:23:88:8d:de:0b:39:38:
64:b5:8b:6b:3d:dc:0c:bd:99:99:97:3f:86:ef:fa:
71:e4:c6:e3:08:f3:a7:0f:62:40:62:62:06:be:06:
cd:d3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Alternative Name:
DNS:example.com
Signature Algorithm: sha256WithRSAEncryption
24:d5:3f:6c:d0:00:68:a2:8e:b1:fb:33:c2:53:ce:0e:af:96:
b3:07:3b:81:96:bc:25:0c:a0:99:2a:8b:15:6e:0b:d5:46:46:
72:0e:c1:dc:dc:be:04:f7:42:9f:f0:16:8d:06:4e:80:59:cb:
13:17:d4:c0:a3:bd:fe:af:bb:83:51:e7:e8:18:84:ec:03:21:
45:86:4a:a0:3a:69:30:76:69:06:e3:f6:c6:cb:6e:57:7f:58:
a8:6e:4d:01:e5:7e:15:5c:50:e4:3f:c6:86:d0:5e:82:5d:2a:
8a:3b:c7:01:bb:fc:90:ab:0d:8c:ea:67:0d:c2:ff:fe:28:47:
88:02:e6:8e:4d:46:8e:90:24:0e:55:11:e7:cf:92:3b:82:03:
54:f8:8b:30:dd:97:2d:5d:61:84:11:49:37:45:9f:a9:b2:aa:
c2:ee:da:64:00:cf:09:67:95:58:23:2e:02:60:b9:9d:c1:d0:
54:3f:df:17:09:f8:b1:f0:11:ed:dd:07:27:5a:09:02:53:0b:
f5:14:cf:9f:db:23:81:e4:a6:a7:f0:91:b0:4a:3c:f1:9e:4e:
fb:8a:ee:fd:db:37:27:f3:2b:40:0d:80:f8:77:ec:5a:c6:18:
bf:a1:66:79:fc:7d:20:f6:26:53:b8:10:da:03:3e:46:61:8c:
fe:d8:c2:ca
■HTTPS通信確認
openssl s_client -connect xxxx.com:443
openssl s_client: OpenSSLコマンドでSSL/TLSクライアントを起動
-connect xxxx.com:443: 接続先のホスト名とポート番号を指定
このコマンドを実行すると、指定されたホストとポート上のサーバーに対してSSL/TLS接続が試みられる。
接続が成功すると、サーバーの証明書情報や使用されるSSL/TLSバージョンなどの詳細な情報が表示される。
証明書ファイルの内容を表示したい場合は以下
openssl x509 -in xxxx.crt -text -noout
■cURL確認(おまけ)
curl http://xxxx.com
-L:リダイレクトがあればリダイレクト先の情報を取得
-s:進捗状況を非表示。-sSとすることが多い
-S:エラーは表示。-sSとすることが多い
-v:詳細ログを出力
-I:HTTPレスポンスヘッダを取得
-k:SSL接続で証明書エラーをスキップ
