HashicorpのVaultはPKI(Public Key Infrastructure、公開鍵基盤)として利用できるらしい。今回はRoot CAの作成、サーバー証明書の作成、クライアント証明書の作成と失効を試した。間違ってたらゴメンなさい。Vaultについての概要はWEB+DB PRESS Vol.104に記事が書かれているので読むとよさそう。
準備
Vaultのバージョンはv0.10.1。macOS用のバイナリをダウンロードして、PATHの通った場所に置いた。
➤ vault version Vault v0.10.1 ('756fdc4587350daf1c65b93647b2cc31a6f119cd')
curlはHomwbrewでインストールし、opensslを使うようにしている。
➤ curl --version curl 7.59.0 (x86_64-apple-darwin16.7.0) libcurl/7.59.0 OpenSSL/1.0.2o zlib/1.2.8 Release-Date: 2018-03-14 Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP UnixSockets HTTPS-proxy
Homebrewでcurlをインストールした時のコマンド。
➤ brew install curl --with-openssl ➤ brew link curl --force
nginxもHomebrewでインストールした。
➤ nginx -v nginx version: nginx/1.13.12
Vault serverサーバーの初期化・ログイン
まずはvault serverを用意する。ファイルで諸々を設定。バックエンドにはファイルを使うことにした。また、vaultのAPIをTLSなしで利用できるようにしておく。
disable_mlock = true listener "tcp" { address = "0.0.0.0:8200" tls_disable = 1 } backend "file" { path = "./secrets" }
シュッと起動。
➤ vault server -config=vault.hcl ==> Vault server configuration: Cgo: disabled Listener 1: tcp (addr: "0.0.0.0:8200", cluster address: "0.0.0.0:8201", tls: "disabled") Log Level: info Mlock: supported: false, enabled: false Storage: file Version: Vault v0.10.1 Version Sha: 756fdc4587350daf1c65b93647b2cc31a6f119cd ==> Vault server started! Log data will stream in below:
ターミナルの別セッションを開いて、initからのunseal、login。このあたりは長いので実行コマンドだけ。
➤ vault init ➤ vault operator unseal R4ltBqjMeWg1ouKU02YeV4wxxc8qAQdQ2xH1m84z+jT1 ➤ vault operator unseal 2MKCTBnYuFlOg1nhdy45dPXrCbQ3zLgQODf7XqGQ5edW ➤ vault operator unseal igJGlnwWqO/S3pH30r6HwylKPSOrA6Ekrw6bQ0YHwtuz ➤ vault login
これで利用準備が整った。
Root CAの作成
まずはRoot CAを作るのだが、vaultでPKIを有効にする必要がある。vault secrets enableコマンドを使う。
➤ vault secrets enable -path=alpaca -description="Alpaca Root CA" -max-lease-ttl=87600h pki Success! Enabled the pki secrets engine at: alpaca/
これで、PKIタイプのsecretとしてalpacaができた。
➤ vault secrets list Path Type Description ---- ---- ----------- alpaca/ pki Alpaca Root CA cubbyhole/ cubbyhole per-token private secret storage identity/ identity identity store secret/ kv key/value secret storage sys/ system system endpoints used for control, policy and debugging
Generate Root APIを使ってRoot CAを作る。
➤ vault write alpaca/root/generate/internal common_name="Alpaca Root CA" ttl=87600h key_bites=4096 exclude_cn_from_sans=true Key Value --- ----- certificate -----BEGIN CERTIFICATE----- MIIDIzCCAgugAwIBAgIUCcDoq0yOld0Y+uzXO14xuMyO/D0wDQYJKoZIhvcNAQEL [snip] IdBHItMaNSwMlOnlTDaYN+YSLBJZNRQhTpqglEKoPKZK6Kcp8pm7 -----END CERTIFICATE----- expiration 1841048532 issuing_ca -----BEGIN CERTIFICATE----- MIIDIzCCAgugAwIBAgIUCcDoq0yOld0Y+uzXO14xuMyO/D0wDQYJKoZIhvcNAQEL [snip] IdBHItMaNSwMlOnlTDaYN+YSLBJZNRQhTpqglEKoPKZK6Kcp8pm7 -----END CERTIFICATE----- serial_number 09:c0:e8:ab:4c:8e:95:dd:18:fa:ec:d7:3b:5e:31:b8:cc:8e:fc:3d
certificate endpoint / crl distribution points などを設定する。set url apiを使う。
➤ ➤ vault write alpaca/config/urls issuing_certificates="http://127.0.0.1:8200/v1/alpaca/ca" crl_distribution_points="http://127.0.0.1:8200/v1/alpaca/crl" Success! Data written to: alpaca/config/urls
Root CAまわりはこれでOK。
SSLサーバー証明書を作る
まず、Create Role APでロールを作る。
➤ vault write alpaca/roles/alpacareplinfo key_bites=2048 max_ttl=8760h allow_any_name=true Success! Data written to: alpaca/roles/alpacareplinfo
Generate Certificate API でCertificateを作る。Private Keyは保存されないので、コマンド実行後に出力されたものを自分で保存しておくこと。certificateとprivate_keyに対応するvalueをファイルに保存する。alpaca.repl.info.crt と alpaca.repl.info.keyとする。
➤ vault write alpaca/issue/alpacareplinfo common_name="alpaca.repl.info" ip_sans="127.0.0.1" ttl=720h foramt=pem Key Value --- ----- certificate -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIUPgktLTjT1Q38xoSajQKaKqPYg2MwDQYJKoZIhvcNAQEL [snip] liCiDZ3EW2BFgi63RNATXLqkg0qnPocKh6UN5Q455+RhxlWdDCXfPEnxjCsSQ2Hy gXd0ExXo4CjQ57pVgNCBU1c9gA0= -----END CERTIFICATE----- issuing_ca -----BEGIN CERTIFICATE----- MIIDIzCCAgugAwIBAgIUCcDoq0yOld0Y+uzXO14xuMyO/D0wDQYJKoZIhvcNAQEL [snip] IdBHItMaNSwMlOnlTDaYN+YSLBJZNRQhTpqglEKoPKZK6Kcp8pm7 -----END CERTIFICATE----- private_key -----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEArxRBksznyg+C0Bd7I/SqIjjo61CT73+3pwQTIb5IWtjiq9D4 [snip] GbS2BirViEYlPy2obPzbhWoHV9KOu1m1ObRz/xaObhEW8FyewklEgMM= -----END RSA PRIVATE KEY----- private_key_type rsa serial_number 3e:09:2d:2d:38:d3:d5:0d:fc:c6:84:9a:8d:02:9a:2a:a3:d8:83:63
nginxに設定する
nginx.confを用意する。ssl_certificateとssl_certificate_keyに先ほど作成したcertificateとprivate_keyを設定する。
➤ cat nginx.conf worker_processes 1; events { worker_connections 1024; } http { server { listen 443 ssl; server_name alpaca.repl.info; ssl_certificate alpaca.repl.info.crt; ssl_certificate_key alpaca.repl.info.key; ssl_protocols TLSv1.2; ssl_ciphers HIGH:!aNULL:!MD5; location / { root /usr/local/var/www; index index.html index.htm; } } }
nginxを起動して…
➤ sudo nginx -c /path/to/nginx.conf
alpaca.repl.infoでnginxにアクセスできるよう、hostsに追記しておく。
➤ grep alpaca.repl.info /etc/hosts 127.0.0.1 localhost alpaca.repl.info
ここで、curlを使ってアクセスしてみる。nginxで設定したサーバー証明書の検証ができないので、以下のようなエラーとなる。
➤ curl https://alpaca.repl.info curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.haxx.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.
insecureオプションをつけて検証しないようにするとアクセスできる。
➤ curl -k https://alpaca.repl.info <html><body><h1>It works!</h1></body></html>
ここで、Root CAのcertificateをca.pemとして用意し、–cacertオプションで指定する。これにより、サーバー証明書の検証を行うことができ、アクセスできる。
➤ curl --cacert ca.pem https://alpaca.repl.info <html><body><h1>It works!</h1></body></html>
クライアント証明書で認証する
認証したい。まずは認証に失敗してアクセスできないことを確認する。nginx.confに設定を追加する。ここではca.pemはRoot CAのcerfiticateを使っている。
ssl_verify_client on; ssl_client_certificate ca.pem;
アクセス不可になることを確認する。
➤ curl --cacert ca.pem https://alpaca.repl.info <html> <head><title>400 No required SSL certificate was sent</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <center>No required SSL certificate was sent</center> <hr><center>nginx/1.13.12</center> </body> </html>
クライアント用の証明書と秘密鍵を作る。サーバー証明書を作った時と同様、ロールを作成して証明書を作る。
➤ vault write alpaca/roles/client001 key_bites=2048 max_ttl=8760h allow_any_name=true Success! Data written to: alpaca/roles/client001
➤ vault write alpaca/issue/client001 common_name="alpaca.repl.info" ip_sans="127.0.0.1" ttl=720h foramt=pem Key Value --- ----- certificate -----BEGIN CERTIFICATE----- MIID0DCCArigAwIBAgIUN9J828bPrc0hAFymYy1bUfHicYcwDQYJKoZIhvcNAQEL [snip] yGQuy/YKoC15E5xuk1+y1oHOYsQNPtOXAXGo2qoGKEn78FKzkYgVEB9MkMaica63 L3f5+JatCMlu9PFUazKsAuzJrxg= -----END CERTIFICATE----- issuing_ca -----BEGIN CERTIFICATE----- MIIDIzCCAgugAwIBAgIUCcDoq0yOld0Y+uzXO14xuMyO/D0wDQYJKoZIhvcNAQEL [snip] 9jVJzSPjoFE3ea+njGR95yxIXT2vD3aznFvShPmlpl7DA/SeeOWe1MtSUb02pcKA IdBHItMaNSwMlOnlTDaYN+YSLBJZNRQhTpqglEKoPKZK6Kcp8pm7 -----END CERTIFICATE----- private_key -----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAw8mDJNdEgf9j8rkcN3mwXYt4hSYDw2P54jBmiuOL4WmbLm1x [snip] A3fqBRhroUMkLXPDfJbhi+YRfcYd1OrhodBTNJreDCZ87eW+tV8kWw== -----END RSA PRIVATE KEY----- private_key_type rsa serial_number 37:d2:7c:db:c6:cf:ad:cd:21:00:5c:a6:63:2d:5b:51:f1:e2:71:87
certificateとprivate_keyをファイルに保存し、curlの–certと–keyオプションで指定することでアクセスに成功する。
➤ curl -k --cert client001.crt --key client001.key https://alpaca.repl.info <html><body><h1>It works!</h1></body></html>
クライアント証明書を失効させてみる
認証で使うのだから、何かあったときには失効させたい。revoke certificate APIがあって、これを使えば失効させられる。
➤ vault write alpaca/revoke serial_number=37:d2:7c:db:c6:cf:ad:cd:21:00:5c:a6:63:2d:5b:51:f1:e2:71:87 Key Value --- ----- revocation_time 1525689460 revocation_time_rfc3339 2018-05-07T10:37:40.219554054Z
失効できたが、これだけだとまだアクセスできる。CRLをnginxが参照していないためである。
➤ curl --cert client001.crt --key client001.key --cacert ca.pem https://alpaca.repl.info <html><body><h1>It works!</h1></body></html>
API経由でcrl.pemを取得する。
➤ curl http://localhost:8200/v1/alpaca/crl/pem > crl.pem
見てみると、失効したシリアルナンバーである”37:d2:7c:db:c6:cf:ad:cd:21:00:5c:a6:63:2d:5b:51:f1:e2:71:87″がrevoked certificatesに含まれていることがわかる。
➤ openssl crl -in crl.pem -text Certificate Revocation List (CRL): Version 2 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: /CN=Alpaca Root CA Last Update: May 7 10:37:40 2018 GMT Next Update: May 10 10:37:40 2018 GMT CRL extensions: X509v3 Authority Key Identifier: keyid:1B:34:31:B1:15:2B:82:E5:48:29:C8:24:D3:D3:FA:7A:26:E5:56:8A Revoked Certificates: Serial Number: 37D27CDBC6CFADCD21005CA6632D5B51F1E27187 Revocation Date: May 7 10:37:40 2018 GMT Signature Algorithm: sha256WithRSAEncryption b3:09:ec:6d:da:01:c1:e2:c6:53:da:25:69:69:2c:f2:ab:60: 1d:41:f2:cd:44:28:60:b0:43:a5:05:6a:80:58:06:ec:a2:e9: 47:35:28:66:b9:60:4e:69:45:bf:95:0a:87:22:36:2d:9c:0c: a0:23:45:35:a0:b3:f6:41:32:d0:8b:21:fe:b5:34:37:4d:fd: 84:78:cb:b7:a6:b4:3d:d4:13:23:4f:8d:53:17:3b:e2:88:af: bf:f5:5e:18:ee:50:97:75:a8:90:29:b6:64:5a:94:f9:eb:a5: c8:ea:03:af:83:72:03:2c:80:26:55:77:ba:6e:e2:be:f5:db: c7:a4:68:f5:1c:07:89:45:98:53:0f:90:eb:23:a3:fd:a3:34: e8:17:7c:58:69:39:1d:86:a0:e1:ee:35:c9:e8:11:63:ed:93: 76:c6:04:98:1d:5c:42:ca:a1:c7:bc:8a:0f:99:18:50:8c:7c: 5f:82:cc:fa:3b:fb:b4:20:ac:5d:92:b7:34:96:38:c9:0a:29: 3d:67:63:a7:f5:f1:f3:5f:61:99:37:53:f8:76:d4:7b:cd:d4: 31:b3:48:6f:1e:68:ff:11:b6:1e:b1:7d:53:b0:c6:b5:d0:e8: 2c:f3:eb:5d:08:49:3c:44:79:b6:17:3a:3f:c5:cb:a3:ed:ba: 57:17:ff:bd -----BEGIN X509 CRL----- MIIBsDCBmQIBATANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQDEw5BbHBhY2EgUm9v dCBDQRcNMTgwNTA3MTAzNzQwWhcNMTgwNTEwMTAzNzQwWjAnMCUCFDfSfNvGz63N IQBcpmMtW1Hx4nGHFw0xODA1MDcxMDM3NDBaoCMwITAfBgNVHSMEGDAWgBQbNDGx FSuC5UgpyCTT0/p6JuVWijANBgkqhkiG9w0BAQsFAAOCAQEAswnsbdoBweLGU9ol aWks8qtgHUHyzUQoYLBDpQVqgFgG7KLpRzUoZrlgTmlFv5UKhyI2LZwMoCNFNaCz 9kEy0Ish/rU0N039hHjLt6a0PdQTI0+NUxc74oivv/VeGO5Ql3WokCm2ZFqU+eul yOoDr4NyAyyAJlV3um7ivvXbx6Ro9RwHiUWYUw+Q6yOj/aM06Bd8WGk5HYag4e41 yegRY+2TdsYEmB1cQsqhx7yKD5kYUIx8X4LM+jv7tCCsXZK3NJY4yQopPWdjp/Xx 819hmTdT+HbUe83UMbNIbx5o/xG2HrF9U7DGtdDoLPPrXQhJPER5thc6P8XLo+26 Vxf/vQ== -----END X509 CRL-----
nginxに設定を追加して、crlを見るようにする。
ssl_crl crl.pem;
再度アクセスを試みるが、bad requestとなり、繋がらなくなることがわかる。
➤ curl --cert client001.crt --key client001.key --cacert ca.pem https://alpaca.repl.info <html> <head><title>400 The SSL certificate error</title></head> <body bgcolor="white"> <center><h1>400 Bad Request</h1></center> <center>The SSL certificate error</center> <hr><center>nginx/1.13.12</center> </body> </html>
ひとまず動いたぞ!という記録だが、結構使えそうだなあという感触を得た。Kubernetesのような、いろんなコンポーネントがバシバシ証明書を必要とする環境で役立ちそうである。今回は証明書の配置を手動で行ったが、Consul Templateと組み合わせて自動配布、なんてこともできるので夢が広がるなあ。また、中間CAを扱うこともできるようなので、そちらも試しておきたい。