step-caを試す
step-ca について
- 簡易CAを立てることができる。
- ACMEプロトコルに対応しているので、certbot コマンドによる証明書発行・更新ができる。
- 発行される証明書の期限はデフォルトで24h。
証明書の期限は(常識の範囲で)短ければ短いほどよい。ツールで自動更新すれば問題ないよね。というポリシー。
不特定多数向けではなくて、閉じたコミュニティ向けなら、頻繁に更新リクエストがあってもサーバ負荷の問題にならないのだと思う。
参考
環境
ざっくり以下の感じでコンテナを作成
FROM alpine:3.16
RUN cd /tmp \
&& wget https://dl.smallstep.com/gh-release/cli/gh-release-header/v0.25.1/step_linux_0.25.1_amd64.tar.gz \
&& wget https://dl.smallstep.com/gh-release/certificates/gh-release-header/v0.25.2/step-ca_linux_0.25.2_amd64.tar.gz \
&& tar xzvf step_linux_0.25.1_amd64.tar.gz \
&& tar xzvf step-ca_linux_0.25.2_amd64.tar.gz \
&& mv step_0.25.1/bin/step /usr/local/bin \
&& mv step-ca /usr/local/bin \
&& rm -rf *.tar.gz LICENSE README.md step_0.25.1
コンテナ起動後、動作確認のために必要なツールも追加
# apk add openssl curl jq certbot
初期化
CA証明書やコンフィグ作成のため初期化を実施。
自分のCA証明書、中間CA証明書を持ち込んで利用することもできる。
# step ca init --acme
_ Deployment Type: Standalone
What would you like to name your new PKI?
_ (e.g. Smallstep): test-ca
What DNS names or IP addresses will clients use to reach your CA?
_ (e.g. ca.example.com[,10.1.2.3,etc.]): 127.0.0.1What IP and port will your new CA bind to? (:443 will bind to 0.0.0.0:443)
_ (e.g. :443 or 127.0.0.1:443): :443
What would you like to name the CA's first provisioner?
_ (e.g. you@smallstep.com): test@example.com
Choose a password for your CA keys and first provisioner.
_ [leave empty and we'll generate one]:
_ Password: password
Generating root certificate... done!
Generating intermediate certificate... done!
_ Root certificate: /root/.step/certs/root_ca.crt
_ Root private key: /root/.step/secrets/root_ca_key
_ Root fingerprint: da894958957a98131a2a3463963946ef7fdd9be7b16302553c56bbc7d702096c
_ Intermediate certificate: /root/.step/certs/intermediate_ca.crt
_ Intermediate private key: /root/.step/secrets/intermediate_ca_key
_ Database folder: /root/.step/db
_ Default configuration: /root/.step/config/defaults.json
_ Certificate Authority configuration: /root/.step/config/ca.json
Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.
以下略
起動
中間証明書の秘密鍵パスフレーズを記載したファイルを準備して起動する
起動したら標準出力を占有するので、以後は別ターミナルを立ち上げて確認していく
# echo password >> ~/.step/config/.incapassword
# chmod 600 ~/.step/config/.incapassword
# step-ca --password-file ~/.step/config/.incapassword ~/.step/config/ca.json
badger 2024/11/30 09:23:18 INFO: All 1 tables opened in 2ms
badger 2024/11/30 09:23:18 INFO: Replaying file id: 0 at offset: 2923
badger 2024/11/30 09:23:18 INFO: Replay took: 17.764_s
2024/11/30 09:23:18 Starting Smallstep CA/0.25.2 (linux/amd64)
2024/11/30 09:23:18 Documentation: https://u.step.sm/docs/ca
2024/11/30 09:23:18 Community Discord: https://u.step.sm/discord
2024/11/30 09:23:18 Config file: /root/.step/config/ca.json
2024/11/30 09:23:18 The primary server URL is https://127.0.0.1:443
2024/11/30 09:23:18 Root certificates are available at https://127.0.0.1:443/roots.pem
2024/11/30 09:23:18 X.509 Root Fingerprint: da894958957a98131a2a3463963946ef7fdd9be7b16302553c56bbc7d702096c
2024/11/30 09:23:18 Serving HTTPS on :443 ...
ルート証明書の確認
ルート証明書は10年有効
# step ca root | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
a3:f3:5a:85:19:f6:1f:35:1d:49:d5:1d:e6:c4:e5:16
Signature Algorithm: ecdsa-with-SHA256
Issuer: O = test-ca, CN = test-ca Root CA
Validity
Not Before: Nov 30 09:14:56 2024 GMT
Not After : Nov 28 09:14:56 2034 GMT
Subject: O = test-ca, CN = test-ca Root CA
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:b0:21:98:79:0f:73:45:64:43:30:28:e7:46:d5:
b5:cd:6f:ae:7e:1b:e3:76:da:e6:0f:98:57:06:d2:
7b:fe:2c:6d:9a:a1:6b:d5:22:92:49:a0:65:72:ed:
33:92:cd:18:44:41:6f:8a:4a:9b:11:fe:a6:63:5b:
31:b5:16:0a:87
ASN1 OID: prime256v1
NIST CURVE: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
X509v3 Subject Key Identifier:
6A:15:B9:8A:90:7C:3F:99:6C:9B:A0:78:2C:5F:69:C8:4A:06:0C:63
Signature Algorithm: ecdsa-with-SHA256
30:46:02:21:00:c5:0e:6a:3c:1d:fd:ae:dd:6f:14:04:52:26:
2d:c0:4e:28:d6:1a:65:fb:b6:61:95:0f:b3:ae:f9:7a:fb:46:
cd:02:21:00:a7:03:69:a1:67:2a:e1:c1:3a:f6:5e:11:cf:b6:
cb:f0:76:37:ac:3a:c9:83:76:b8:e0:83:04:6a:3a:82:b3:6e
ルート証明書をファイルへ保存。内容の確認。
# step ca root step-ca.crt
The root certificate has been saved in step-ca.crt.
# step certificate inspect step-ca.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 217927727411809861814856199213165110550 (0xa3f35a8519f61f351d49d51de6c4e516)
Signature Algorithm: ECDSA-SHA256
Issuer: O=test-ca,CN=test-ca Root CA
Validity
Not Before: Nov 30 09:14:56 2024 UTC
Not After : Nov 28 09:14:56 2034 UTC
Subject: O=test-ca,CN=test-ca Root CA
Subject Public Key Info:
Public Key Algorithm: ECDSA
Public-Key: (256 bit)
X:
b0:21:98:79:0f:73:45:64:43:30:28:e7:46:d5:b5:
cd:6f:ae:7e:1b:e3:76:da:e6:0f:98:57:06:d2:7b:
fe:2c
Y:
6d:9a:a1:6b:d5:22:92:49:a0:65:72:ed:33:92:cd:
18:44:41:6f:8a:4a:9b:11:fe:a6:63:5b:31:b5:16:
0a:87
Curve: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:1
X509v3 Subject Key Identifier:
6A:15:B9:8A:90:7C:3F:99:6C:9B:A0:78:2C:5F:69:C8:4A:06:0C:63
Signature Algorithm: ECDSA-SHA256
30:46:02:21:00:c5:0e:6a:3c:1d:fd:ae:dd:6f:14:04:52:26:
2d:c0:4e:28:d6:1a:65:fb:b6:61:95:0f:b3:ae:f9:7a:fb:46:
cd:02:21:00:a7:03:69:a1:67:2a:e1:c1:3a:f6:5e:11:cf:b6:
cb:f0:76:37:ac:3a:c9:83:76:b8:e0:83:04:6a:3a:82:b3:6e
step-ca サーバへの通信確認
自己署名なので、ルート証明書を指定しないとエラーになる。ルート証明書を指定すると正常。
# curl -I https://127.0.0.1/
curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
# curl --cacert step-ca.crt -I https://127.0.0.1/
HTTP/2 404
content-type: text/plain; charset=utf-8
x-content-type-options: nosniff
content-length: 19
date: Sat, 30 Nov 2024 09:29:36 GMT
ルート→中間→サーバ証明書のチェーンになっている
# openssl s_client -connect 127.0.0.1:443 -CAfile step-ca.crt < /dev/null [27/1806]
CONNECTED(00000003)
Can't use SSL_get_servername
depth=2 O = test-ca, CN = test-ca Root CA
verify return:1
depth=1 O = test-ca, CN = test-ca Intermediate CA
verify return:1
depth=0 CN = Step Online CA
verify return:1
---
Certificate chain
0 s:CN = Step Online CA
i:O = test-ca, CN = test-ca Intermediate CA
1 s:O = test-ca, CN = test-ca Intermediate CA
i:O = test-ca, CN = test-ca Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIBzjCCAXWgAwIBAgIQD7fGggHkr5hLbM7PUgGmwTAKBggqhkjOPQQDAjA0MRAw
DgYDVQQKEwd0ZXN0LWNhMSAwHgYDVQQDExd0ZXN0LWNhIEludGVybWVkaWF0ZSBD
QTAeFw0yNDExMzAwOTIyMThaFw0yNDEyMDEwOTIzMThaMBkxFzAVBgNVBAMTDlN0
ZXAgT25saW5lIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVpy7Y/6hLqyd
rPnlxxa2Qw0rPT3iBQwXvlblXkbrpea0E0AwINlwvqJ0k1dWSpNOags5Z0cYGAnb
UzsztjMC4qOBgzCBgDAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH
AwEGCCsGAQUFBwMCMB0GA1UdDgQWBBSjlF9dGQDy3JBkA/RxZeLNfb+1MjAfBgNV
HSMEGDAWgBTZUhSPO1vLv3IOeD+Ju+3K/9fSfzAPBgNVHREECDAGhwR/AAABMAoG
CCqGSM49BAMCA0cAMEQCIGMsoFjHvNlfJAIkC8MBQVRx35jERy30mz6Xr5EcnYb+
AiAIhR/0TK9Y5C3hW/e7OeRWmCz8PfOsIslMf29VNBjwfA==
-----END CERTIFICATE-----
subject=CN = Step Online CA
issuer=O = test-ca, CN = test-ca Intermediate CA
---
Acceptable client certificate CA names
O = test-ca, CN = test-ca Root CA
O = test-ca, CN = test-ca Intermediate CA
Requested Signature Algorithms: RSA-PSS+SHA256:ECDSA+SHA256:Ed25519:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA384:ECDSA+SHA512:RSA+SHA1:ECDSA+SHA1
Shared Requested Signature Algorithms: RSA-PSS+SHA256:ECDSA+SHA256:Ed25519:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA384:ECDSA+SHA512
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1458 bytes and written 387 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Server public key is 256 bit
Secure Renegotiation IS NOT supported
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
以下略
step-ca のサーバ証明書の確認
# openssl s_client -connect 127.0.0.1:443 -CAfile step-ca.crt -showcerts < /dev/null 2> /dev/null | openssl x509 -noout -subject -issuer -dates
subject=CN = Step Online CA
issuer=O = test-ca, CN = test-ca Intermediate CA
notBefore=Nov 30 09:22:18 2024 GMT
notAfter=Dec 1 09:23:18 2024 GMT
利用している設定ファイル等
# find ~/.step -type f
/root/.step/secrets/root_ca_key
/root/.step/secrets/intermediate_ca_key
/root/.step/config/.incapassword
/root/.step/config/ca.json
/root/.step/config/defaults.json
/root/.step/certs/intermediate_ca.crt
/root/.step/certs/root_ca.crt
/root/.step/db/000000.vlog
/root/.step/db/MANIFEST
/root/.step/db/000004.sst
/root/.step/db/LOCK
/root/.step/db/KEYREGISTRY
中間証明書はこれ
# step certificate inspect ~/.step/certs/intermediate_ca.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 133154066476267579855953253187167002732 (0x642c8a56a115957eaafec6127ff5206c)
Signature Algorithm: ECDSA-SHA256
Issuer: O=test-ca,CN=test-ca Root CA
Validity
Not Before: Nov 30 09:14:57 2024 UTC
Not After : Nov 28 09:14:57 2034 UTC
Subject: O=test-ca,CN=test-ca Intermediate CA
Subject Public Key Info:
Public Key Algorithm: ECDSA
Public-Key: (256 bit)
X:
ed:3f:d9:d6:50:55:ef:ec:4a:91:56:06:8f:c1:f2:
6a:77:2f:98:b3:00:87:ed:32:2a:04:14:fa:5f:b2:
0e:89
Y:
57:98:b2:10:15:05:d7:a6:bf:43:eb:5e:f6:68:d0:
7a:59:87:44:e5:44:7b:52:d3:fe:ac:44:c1:45:c8:
71:0f
Curve: P-256
X509v3 extensions:
X509v3 Key Usage: critical
Certificate Sign, CRL Sign
X509v3 Basic Constraints: critical
CA:TRUE, pathlen:0
X509v3 Subject Key Identifier:
D9:52:14:8F:3B:5B:CB:BF:72:0E:78:3F:89:BB:ED:CA:FF:D7:D2:7F
X509v3 Authority Key Identifier:
keyid:6A:15:B9:8A:90:7C:3F:99:6C:9B:A0:78:2C:5F:69:C8:4A:06:0C:63
Signature Algorithm: ECDSA-SHA256
30:45:02:21:00:d8:d9:2c:3b:21:d5:3d:e4:e3:ce:bb:45:78:
c3:75:45:40:16:92:c4:9c:dc:87:fd:95:52:ef:d1:c2:c0:12:
cc:02:20:0f:75:c5:93:36:85:b9:5e:7a:4f:34:51:21:2a:e1:
0d:c0:1a:34:36:ff:12:ff:28:c3:c3:86:8c:c4:8e:21:aa
# step certificate inspect ~/.step/certs/intermediate_ca.crt -short
X.509v3 Intermediate CA Certificate (ECDSA P-256) [Serial: 1331...2732]
Subject: test-ca Intermediate CA
Issuer: test-ca Root CA
Valid from: 2024-11-30T09:14:57Z
to: 2034-11-28T09:14:57Z
証明書を発行してみる
# step ca certificate test-server test-server.crt test-server.key
_ Provisioner: test@example.com (JWK) [kid: XKZEoFeanH7buJ2aXTFToOjRdhjDMdJYeoC2f56x8zI]
Please enter the password to decrypt the provisioner key:
_ CA: https://127.0.0.1
_ Certificate: test-server.crt
_ Private Key: test-server.key
証明書確認
# step certificate inspect test-server.crt --short
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 3117...7905]
Subject: test-server
Issuer: test-ca Intermediate CA
Provisioner: test@example.com [ID: XKZE...x8zI]
Valid from: 2024-11-30T09:42:24Z
to: 2024-12-01T09:43:24Z
CSRの作成と、CAによる署名
CSRの作成
# step certificate create --csr createcsr createcsr.csr createcsr.key
Please enter the password to encrypt the private key:
Your certificate signing request has been saved in createcsr.csr.
Your private key has been saved in createcsr.key.
できたCSRの確認
# openssl req -in createcsr.csr -noout -text
Certificate Request:
Data:
Version: 1 (0x0)
Subject: CN = createcsr
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:49:fe:cd:17:2b:e8:20:89:7c:9f:06:9f:66:6f:
cf:72:82:fd:75:45:cd:b5:9b:53:a7:98:f4:40:5b:
ea:1e:ca:5d:8c:bb:c2:4e:08:40:ba:a8:d1:a2:ce:
c8:99:22:87:33:ba:36:7f:85:f9:f6:f2:42:a9:ef:
33:d7:3b:ce:d9
ASN1 OID: prime256v1
NIST CURVE: P-256
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:createcsr
Signature Algorithm: ecdsa-with-SHA256
30:45:02:20:6d:71:3b:86:9b:b6:9b:9e:49:79:84:ad:a7:81:
2b:43:b0:2d:85:80:8f:ad:15:d7:11:3f:a4:6b:1c:13:e6:a4:
02:21:00:8f:44:e1:1d:93:9b:56:d1:29:8d:7f:52:91:39:c8:
2d:57:05:b0:5a:62:aa:73:0f:95:53:cf:12:c5:37:6c:8a
署名
# step ca sign createcsr.csr createcsr.crt
_ Provisioner: test@example.com (JWK) [kid: XKZEoFeanH7buJ2aXTFToOjRdhjDMdJYeoC2f56x8zI]
Please enter the password to decrypt the provisioner key:
_ CA: https://127.0.0.1
_ Certificate: createcsr.crt
証明書確認
# step certificate inspect createcsr.crt --short
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 1188...7407]
Subject: createcsr
Issuer: test-ca Intermediate CA
Provisioner: test@example.com [ID: XKZE...x8zI]
Valid from: 2024-11-30T09:51:22Z
to: 2024-12-01T09:52:22Z
証明書更新
# step ca renew createcsr.crt createcsr.key
Please enter the password to decrypt createcsr.key:
_ Would you like to overwrite createcsr.crt [y/n]: y
Your certificate has been saved in createcsr.crt.
証明書だけ更新される。キーは更新されない。
# ls -l createcsr.*
-rw------- 1 root root 1478 Nov 30 09:54 createcsr.crt
-rw------- 1 root root 408 Nov 30 09:51 createcsr.csr
-rw------- 1 root root 314 Nov 30 09:51 createcsr.key
# step certificate inspect createcsr.crt --short
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 1213...5791]
Subject: createcsr
Issuer: test-ca Intermediate CA
Provisioner: test@example.com [ID: XKZE...x8zI]
Valid from: 2024-11-30T09:52:54Z
to: 2024-12-01T09:53:54Z
証明書の取り消し
# step ca revoke --cert test-server.crt --key test-server.key
_ CA: https://127.0.0.1
Certificate with Serial Number 31171324922254081302523519979341437905 has been revoked.
取り消された証明書は更新できない
# step ca renew test-server.crt test-server.key
The request lacked necessary authorization to be completed. Please see the certificate authority logs for more info.
Re-run with STEPDEBUG=1 for more info.
シリアルを指定した取り消し
# step certificate inspect --format=json createcsr.crt | jq -r .serial_number
121329645882914692314971445933256135791
# step ca revoke $(step certificate inspect --format=json createcsr.crt | jq -r .serial_number)
_ Provisioner: test@example.com (JWK) [kid: XKZEoFeanH7buJ2aXTFToOjRdhjDMdJYeoC2f56x8zI]
Please enter the password to decrypt the provisioner key:
_ CA: https://127.0.0.1
Certificate with Serial Number 121329645882914692314971445933256135791 has been revoked.
取り消された証明書は更新できない
# step ca renew createcsr.crt createcsr.key
Please enter the password to decrypt createcsr.key:
The request lacked necessary authorization to be completed. Please see the certificate authority logs for more info.
Re-run with STEPDEBUG=1 for more info.
動作確認
あらためてサーバ証明書発行
# step ca certificate test-server test-server.crt test-server.key
_ Provisioner: test@example.com (JWK) [kid: XKZEoFeanH7buJ2aXTFToOjRdhjDMdJYeoC2f56x8zI]
Please enter the password to decrypt the provisioner key:
_ CA: https://127.0.0.1
_ Would you like to overwrite test-server.crt [y/n]: y
_ Would you like to overwrite test-server.key [y/n]: y
_ Certificate: test-server.crt
_ Private Key: test-server.key
サーバ起動
# openssl s_server -key test-server.key -cert test-server.crt -CAfile /root/.step/certs/intermediate_ca.crt
クライアント側から接続
# openssl s_client -CAfile step-ca.crt < /dev/null
CONNECTED(00000003)
depth=2 O = test-ca, CN = test-ca Root CA
verify return:1
depth=1 O = test-ca, CN = test-ca Intermediate CA
verify return:1
depth=0 CN = test-server
verify return:1
---
Certificate chain
0 s:CN = test-server
i:O = test-ca, CN = test-ca Intermediate CA
1 s:O = test-ca, CN = test-ca Intermediate CA
i:O = test-ca, CN = test-ca Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICKjCCAc+gAwIBAgIQIb0elTDAtY5dCDCtE8x3aTAKBggqhkjOPQQDAjA0MRAw
DgYDVQQKEwd0ZXN0LWNhMSAwHgYDVQQDExd0ZXN0LWNhIEludGVybWVkaWF0ZSBD
QTAeFw0yNDExMzAxMDAwNDlaFw0yNDEyMDExMDAxNDlaMBYxFDASBgNVBAMTC3Rl
c3Qtc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYXiHMjafxwpmatz+
UUEoWqeLMoC1hY4j1SUR6KY+bifDwYFdOzqRiw4n8CpBRYijgWoyjZBqg+XwktfT
JK8iM6OB4DCB3TAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMB0GA1UdDgQWBBRA5ZhlGWusRh6CAoG/zKExm19QMTAfBgNVHSME
GDAWgBTZUhSPO1vLv3IOeD+Ju+3K/9fSfzAWBgNVHREEDzANggt0ZXN0LXNlcnZl
cjBUBgwrBgEEAYKkZMYoQAEERDBCAgEBBBB0ZXN0QGV4YW1wbGUuY29tBCtYS1pF
b0ZlYW5IN2J1SjJhWFRGVG9PalJkaGpETWRKWWVvQzJmNTZ4OHpJMAoGCCqGSM49
BAMCA0kAMEYCIQCM44RjT/tDJqNzqlOGjriitdzzG6EI1xAsJxp2MSDQPgIhALHC
qL387ZfoKnegT34JWMh6kZV5LGVVJW+XHv6aenIM
-----END CERTIFICATE-----
subject=CN = test-server
issuer=O = test-ca, CN = test-ca Intermediate CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1390 bytes and written 391 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
以下略
クライアント証明書テスト
クライアント証明書発行
# step ca certificate test@example.net test-client.crt test-client.key
_ Provisioner: test@example.com (JWK) [kid: XKZEoFeanH7buJ2aXTFToOjRdhjDMdJYeoC2f56x8zI]
Please enter the password to decrypt the provisioner key: _
_ CA: https://127.0.0.1
_ Certificate: test-client.crt
_ Private Key: test-client.key
# step certificate inspect test-client.crt -short
X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2554...8132]
Subject: test@example.net
Issuer: test-ca Intermediate CA
Provisioner: test@example.com [ID: XKZE...x8zI]
Valid from: 2024-11-30T10:08:31Z
to: 2024-12-01T10:09:31Z
動作確認のため中間証明書とルート証明書のチェーン作成
# cat /root/.step/certs/intermediate_ca.crt step-ca.crt > chain.crt
クライアント証明書の検証
# openssl verify -purpose sslclient -CAfile chain.crt test-client.crt
test-client.crt: OK
サーバ起動
# openssl s_server -cert test-server.crt -key test-server.key -CAfile /root/.step/certs/intermediate_ca.crt -Verify 2
クライアント証明書を指定して、クライアント側から接続
# openssl s_client -cert test-client.crt -key test-client.key -CAfile chain.crt < /dev/null
CONNECTED(00000003)
depth=2 O = test-ca, CN = test-ca Root CA
verify return:1
depth=1 O = test-ca, CN = test-ca Intermediate CA
verify return:1
depth=0 CN = test-server
verify return:1
---
Certificate chain
0 s:CN = test-server
i:O = test-ca, CN = test-ca Intermediate CA
1 s:O = test-ca, CN = test-ca Intermediate CA
i:O = test-ca, CN = test-ca Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICKjCCAc+gAwIBAgIQIb0elTDAtY5dCDCtE8x3aTAKBggqhkjOPQQDAjA0MRAw
DgYDVQQKEwd0ZXN0LWNhMSAwHgYDVQQDExd0ZXN0LWNhIEludGVybWVkaWF0ZSBD
QTAeFw0yNDExMzAxMDAwNDlaFw0yNDEyMDExMDAxNDlaMBYxFDASBgNVBAMTC3Rl
c3Qtc2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEYXiHMjafxwpmatz+
UUEoWqeLMoC1hY4j1SUR6KY+bifDwYFdOzqRiw4n8CpBRYijgWoyjZBqg+XwktfT
JK8iM6OB4DCB3TAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMB0GA1UdDgQWBBRA5ZhlGWusRh6CAoG/zKExm19QMTAfBgNVHSME
GDAWgBTZUhSPO1vLv3IOeD+Ju+3K/9fSfzAWBgNVHREEDzANggt0ZXN0LXNlcnZl
cjBUBgwrBgEEAYKkZMYoQAEERDBCAgEBBBB0ZXN0QGV4YW1wbGUuY29tBCtYS1pF
b0ZlYW5IN2J1SjJhWFRGVG9PalJkaGpETWRKWWVvQzJmNTZ4OHpJMAoGCCqGSM49
BAMCA0kAMEYCIQCM44RjT/tDJqNzqlOGjriitdzzG6EI1xAsJxp2MSDQPgIhALHC
qL387ZfoKnegT34JWMh6kZV5LGVVJW+XHv6aenIM
-----END CERTIFICATE-----
subject=CN = test-server
issuer=O = test-ca, CN = test-ca Intermediate CA
---
Acceptable client certificate CA names
O = test-ca, CN = test-ca Intermediate CA
Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:ECDSA+SHA1:RSA+S
HA224:RSA+SHA1
Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512
Peer signing digest: SHA256
Peer signature type: ECDSA
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1522 bytes and written 1978 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 256 bit
Secure Renegotiation IS NOT supported
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
以下略
ACME プロトコルを試す
あらためて起動状態を確認
# netstat -apn | grep step-ca
tcp 0 0 :::443 :::* LISTEN 147/step-ca
# step ca health
ok
# curl --cacert step-ca.crt -s https://127.0.0.1/acme/acme/directory | jq
{
"newNonce": "https://127.0.0.1/acme/acme/new-nonce",
"newAccount": "https://127.0.0.1/acme/acme/new-account",
"newOrder": "https://127.0.0.1/acme/acme/new-order",
"revokeCert": "https://127.0.0.1/acme/acme/revoke-cert",
"keyChange": "https://127.0.0.1/acme/acme/key-change"
}
HTTP-01によるチャレンジを試すため、Webサーバに対して名前解決できるようにしておく。
# echo "192.168.11.101 nginx" | tee -a /etc/hosts
192.168.11.101 nginx
# curl -I 192.168.11.101
HTTP/1.1 200 OK
Server: nginx/1.22.1
Date: Sat, 30 Nov 2024 20:30:30 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Sat, 23 Nov 2024 07:57:42 GMT
Connection: keep-alive
ETag: "67418af6-267"
Accept-Ranges: bytes
証明書発行
ローカルに証明書ファイルを作成すべく以下を実行
# REQUESTS_CA_BUNDLE=step-ca.crt \
> certbot certonly \
> --server https://127.0.0.1/acme/acme/directory \
> -d nginx \
> -m test@example.net \
> --manual \
> --preferred-challenges http-01
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing, once your first certificate is successfully issued, to
share your email address with the Electronic Frontier Foundation, a founding
partner of the Let's Encrypt project and the non-profit organization that
develops Certbot? We'd like to send you email about our work encrypting the web,
EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: No
Account registered.
Requesting a certificate for nginx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:
5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK.M13WM1XeTv86-APyMRu5JmNC2EDXriJtyj36DmsS1sU
And make it available on your web server at this URL:
http://nginx/.well-known/acme-challenge/5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
示されたとおり、Webサーバ側でファイルを作成。
$ sudo mkdir -p /var/www/html/.well-known/acme-challenge
$ sudo vi /var/www/html/.well-known/acme-challenge/5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK
$ ls -l /var/www/html/.well-known/acme-challenge/5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK
-rw-r--r-- 1 root root 77 Dec 1 05:33 /var/www/html/.well-known/acme-challenge/5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK
$ cat /var/www/html/.well-known/acme-challenge/5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK
5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK.M13WM1XeTv86-APyMRu5JmNC2EDXriJtyj36DmsS1sU
certbot でエンターキーを押すと、以下のように証明書が作成される。
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/nginx/fullchain.pem
Key is saved at: /etc/letsencrypt/live/nginx/privkey.pem
This certificate expires on 2024-12-01.
These files will be updated when the certificate renews.
NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Webサーバのアクセスログ
$ tail -f /var/log/nginx/access.log
192.168.11.249 - - [01/Dec/2024:05:33:26 +0900] "GET /.well-known/acme-challenge/5LeCmSVd5OWCEZ8qrMDrXX458vjOj3tK HTTP/1.1" 200 77 "-" "Go-http-client/1.1"
作成されたファイル
# ls -l /etc/letsencrypt/live/nginx
total 4
-rw-r--r-- 1 root root 692 Nov 30 20:33 README
lrwxrwxrwx 1 root root 29 Nov 30 20:33 cert.pem -> ../../archive/nginx/cert1.pem
lrwxrwxrwx 1 root root 30 Nov 30 20:33 chain.pem -> ../../archive/nginx/chain1.pem
lrwxrwxrwx 1 root root 34 Nov 30 20:33 fullchain.pem -> ../../archive/nginx/fullchain1.pem
lrwxrwxrwx 1 root root 32 Nov 30 20:33 privkey.pem -> ../../archive/nginx/privkey1.pem
作成されたサーバ証明書の内容
# step certificate inspect /etc/letsencrypt/live/nginx/cert.pem -short
X.509v3 TLS Certificate (RSA 2048) [Serial: 2149...1555]
Subject: nginx
Issuer: test-ca Intermediate CA
Provisioner: acme
Valid from: 2024-11-30T20:31:26Z
to: 2024-12-01T20:32:26Z
中間証明書
# step certificate inspect /etc/letsencrypt/live/nginx/chain.pem -short
X.509v3 Intermediate CA Certificate (ECDSA P-256) [Serial: 1331...2732]
Subject: test-ca Intermediate CA
Issuer: test-ca Root CA
Valid from: 2024-11-30T09:14:57Z
to: 2034-11-28T09:14:57Z
fullchain.pem は、サーバ証明書と中間証明書の合体
# cat /etc/letsencrypt/live/nginx/cert.pem /etc/letsencrypt/live/nginx/chain.pem | diff - /etc/letsencrypt/live/nginx/fullchain.pem | wc -l
0
更新
エラーとなったやり方
# REQUESTS_CA_BUNDLE=step-ca.crt \
> certbot renew \
> --dry-run \
> --server https://127.0.0.1/acme/acme/directory \
> -d nginx
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Currently, the renew verb is capable of either renewing all installed certificates that are due to be renewed or renewing a single certificate specified by its name. If you would like to renew specific certificates by their domains, use
the certonly command instead. The renew verb may provide other options for selecting certificates to renew in the future.
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
# REQUESTS_CA_BUNDLE=step-ca.crt \
> certbot renew \
> --dry-run \
> --server https://127.0.0.1/acme/acme/directory
Saving debug log to /var/log/letsencrypt/letsencrypt.log
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Processing /etc/letsencrypt/renewal/nginx.conf
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Failed to renew certificate nginx with error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.')
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
All simulated renewals failed. The following certificates could not be renewed:
/etc/letsencrypt/live/nginx/fullchain.pem (failure)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 renew failure(s), 0 parse failure(s)
Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.
普通に、再度発行することで、更新できた。
# REQUESTS_CA_BUNDLE=step-ca.crt \
> certbot certonly \
> --server https://127.0.0.1/acme/acme/directory \
> -d nginx \
> -m mnod@example.net \
> --manual \
> --preferred-challenges http-01
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Renewing an existing certificate for nginx
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Create a file containing just this data:
MlGyLe1LxS7uoPThoaSnrvMCMQcware7.M13WM1XeTv86-APyMRu5JmNC2EDXriJtyj36DmsS1sU
And make it available on your web server at this URL:
http://nginx/.well-known/acme-challenge/MlGyLe1LxS7uoPThoaSnrvMCMQcware7
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Webサーバでの操作
$ sudo vi /var/www/html/.well-known/acme-challenge/MlGyLe1LxS7uoPThoaSnrvMCMQcware7
$ ls -l /var/www/html/.well-known/acme-challenge/MlGyLe1LxS7uoPThoaSnrvMCMQcware7
-rw-r--r-- 1 root root 77 Dec 1 05:48 /var/www/html/.well-known/acme-challenge/MlGyLe1LxS7uoPThoaSnrvMCMQcware7
$ cat /var/www/html/.well-known/acme-challenge/MlGyLe1LxS7uoPThoaSnrvMCMQcware7
MlGyLe1LxS7uoPThoaSnrvMCMQcware7.M13WM1XeTv86-APyMRu5JmNC2EDXriJtyj36DmsS1sU
エンターキー押下後のCertbotからの出力
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/nginx/fullchain.pem
Key is saved at: /etc/letsencrypt/live/nginx/privkey.pem
This certificate expires on 2024-12-01.
These files will be updated when the certificate renews.
NEXT STEPS:
- This certificate will not be renewed automatically. Autorenewal of --manual certificates requires the use of an authentication hook script (--manual-auth-hook) but one was not provided. To renew this certificate, repeat this same certbot command before the certificate's expiry date.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
* Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
* Donating to EFF: https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
証明書確認
# step certificate inspect /etc/letsencrypt/live/nginx/cert.pem -short
X.509v3 TLS Certificate (RSA 2048) [Serial: 1973...1817]
Subject: nginx
Issuer: test-ca Intermediate CA
Provisioner: acme
Valid from: 2024-11-30T20:46:54Z
to: 2024-12-01T20:47:54Z
接続確認
サーバ起動
openssl s_server -key /etc/letsencrypt/live/nginx/privkey.pem -cert /etc/letsencrypt/live/nginx/cert.pem -CAfile /etc/letsencrypt/live/nginx/chain.pem
クライアント側から接続
# openssl s_client -CAfile step-ca.crt < /dev/null
CONNECTED(00000003)
depth=2 O = test-ca, CN = test-ca Root CA
verify return:1
depth=1 O = test-ca, CN = test-ca Intermediate CA
verify return:1
depth=0
verify return:1
---
Certificate chain
0 s:
i:O = test-ca, CN = test-ca Intermediate CA
1 s:O = test-ca, CN = test-ca Intermediate CA
i:O = test-ca, CN = test-ca Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICpTCCAkugAwIBAgIRAJR2l8T/t0ygiCpfOEDLKAkwCgYIKoZIzj0EAwIwNDEQ
MA4GA1UEChMHdGVzdC1jYTEgMB4GA1UEAxMXdGVzdC1jYSBJbnRlcm1lZGlhdGUg
Q0EwHhcNMjQxMTMwMjA0NjU0WhcNMjQxMjAxMjA0NzU0WjAAMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsFPb4MYa2QW8mWYRenuyCooj+DW5C8b0GgZW
c3KT6C2OwWTTbsv/z0UCYqKvxne4VLBXlZI7ph3imtzmJBjP7hI+gkIVE+QssgVh
OxvZmalDCD1yGXKkqGg4LwiGstkUoshT7eRbwXnACHXcMPM5bPqQFDT5XMQLAZvC
0AFBUQ3TETdnBSw703grPc1z9u4RWNHALvk6CXW1xTanG9QS9HOP/TVa27Q/v95i
8BxXkQxzQu+C4Ik/cBLfE+zRcMpbhcOhfduQZfsZH8PW4fnOZ5txjz750xRCyHq4
KXMrlS3lp6Fy+UXGDEP+Mk4QHXJ1lAn7p7gIpzBJe7PKUii/HQIDAQABo4GmMIGj
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
HQYDVR0OBBYEFC0SS5lCG4TELGwjiX+u4tB1d1P7MB8GA1UdIwQYMBaAFNlSFI87
W8u/cg54P4m77cr/19J/MBMGA1UdEQEB/wQJMAeCBW5naW54MB0GDCsGAQQBgqRk
xihAAQQNMAsCAQYEBGFjbWUEADAKBggqhkjOPQQDAgNIADBFAiEA2D1v/zGHuW6d
r9QRFgTxX2mPG2LBfP+DW8ZDybu39FACIDdCbMHzJgFQB4+zMdH3OwT7YdKFzACy
T3KtPgEd18J3
-----END CERTIFICATE-----
subject=
issuer=O = test-ca, CN = test-ca Intermediate CA
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1698 bytes and written 391 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
以下略
クライアント証明書を利用した接続確認
サーバ起動
# openssl s_server -key /etc/letsencrypt/live/nginx/privkey.pem -cert /etc/letsencrypt/live/nginx/cert.pem -CAfile /etc/letsencrypt/live/nginx/chain.pem -Verify 2
クライアント証明書を利用して、クライアント側から接続
# openssl s_client -cert test-client.crt -key test-client.key -CAfile chain.crt < /dev/null [144/1886]
CONNECTED(00000003)
depth=2 O = test-ca, CN = test-ca Root CA
verify return:1
depth=1 O = test-ca, CN = test-ca Intermediate CA
verify return:1
depth=0
verify return:1
---
Certificate chain
0 s:
i:O = test-ca, CN = test-ca Intermediate CA
1 s:O = test-ca, CN = test-ca Intermediate CA
i:O = test-ca, CN = test-ca Root CA
---
Server certificate
-----BEGIN CERTIFICATE-----
MIICpTCCAkugAwIBAgIRAJR2l8T/t0ygiCpfOEDLKAkwCgYIKoZIzj0EAwIwNDEQ
MA4GA1UEChMHdGVzdC1jYTEgMB4GA1UEAxMXdGVzdC1jYSBJbnRlcm1lZGlhdGUg
Q0EwHhcNMjQxMTMwMjA0NjU0WhcNMjQxMjAxMjA0NzU0WjAAMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsFPb4MYa2QW8mWYRenuyCooj+DW5C8b0GgZW
c3KT6C2OwWTTbsv/z0UCYqKvxne4VLBXlZI7ph3imtzmJBjP7hI+gkIVE+QssgVh
OxvZmalDCD1yGXKkqGg4LwiGstkUoshT7eRbwXnACHXcMPM5bPqQFDT5XMQLAZvC
0AFBUQ3TETdnBSw703grPc1z9u4RWNHALvk6CXW1xTanG9QS9HOP/TVa27Q/v95i
8BxXkQxzQu+C4Ik/cBLfE+zRcMpbhcOhfduQZfsZH8PW4fnOZ5txjz750xRCyHq4
KXMrlS3lp6Fy+UXGDEP+Mk4QHXJ1lAn7p7gIpzBJe7PKUii/HQIDAQABo4GmMIGj
MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw
HQYDVR0OBBYEFC0SS5lCG4TELGwjiX+u4tB1d1P7MB8GA1UdIwQYMBaAFNlSFI87
W8u/cg54P4m77cr/19J/MBMGA1UdEQEB/wQJMAeCBW5naW54MB0GDCsGAQQBgqRk
xihAAQQNMAsCAQYEBGFjbWUEADAKBggqhkjOPQQDAgNIADBFAiEA2D1v/zGHuW6d
r9QRFgTxX2mPG2LBfP+DW8ZDybu39FACIDdCbMHzJgFQB4+zMdH3OwT7YdKFzACy
T3KtPgEd18J3
-----END CERTIFICATE-----
subject=
issuer=O = test-ca, CN = test-ca Intermediate CA
---
Acceptable client certificate CA names
O = test-ca, CN = test-ca Intermediate CA
Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:ECDSA+SHA1:RSA+S
HA224:RSA+SHA1
Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512
Peer signing digest: SHA256
Peer signature type: RSA-PSS
Server Temp Key: X25519, 253 bits
---
SSL handshake has read 1831 bytes and written 1979 bytes
Verification: OK
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)
以下略
所感
- 自前で作成したルート証明書と中間証明書を用意して証明書を発行する仕組みをやってみたい。
- 中間証明書の発行・更新は自分でやるのだろうなぁ。
- SSH証明書も対応してるようなので、それも試したい。
- コンテナとかAnsibleとか使ったデプロイ、CI/CDの仕組みまでできると美味いのだろうと思った。
Discussion