repl.info

Hashicorp VaultのPKI Secerts Engineを試す

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を扱うこともできるようなので、そちらも試しておきたい。