3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CloudflareAdvent Calendar 2022

Day 14

Cloudflare Keyless SSL を使ってみる

Last updated at Posted at 2023-04-25

Keyless SSL とは

顧客から外部(Cloudflare)にプライベートキー(秘密鍵)をアップロードすることなく、SSL 終端を行えるサービスです。

キーレスSSLは、CloudflareのSSLサービスを使用しながら、顧客がプライベートキーをオンプレミスで保持することができるようになりました。

標準的なCloudflare SSLサービスでは、顧客は自分のサイトのSSLキーをCloudflareと共有する必要があります。 Cloudflareは顧客のキー情報を保護するために広範囲な技術的措置を講じています。ただし、一部の顧客にはポリシーや技術上の障壁があるため、自分のサイトのSSLキーをCloudflareと共有することができません。このため、「Keyless SSL」を紹介することに興奮しています。

キーレスSSLはエンタープライズプランのお客様のみ利用可能です。エンタープライズプランとキーレスSSLに関する詳細情報については、Cloudflare 営業チームまでお問い合わせください。

[LOGICAL DIAGRAM SHOWING PRIVATE KEYS STORED ON HSMs BEING USED FOR TLS HANDSHAKE]

プライベートキー(秘密鍵)に関して整理すると、以下の表のようになります。

プライベートキー(秘密鍵)を自社で持ちたくない・運用管理したくないという場合は、代わりに Cloudflare が保管・運用管理するモデルが良いでしょう。

逆にプライベートキー(秘密鍵)を外部に出したくない・出せない(業界セキュリティ標準の要請などの)場合には Keyless SSL が良いでしょう。

プライベートキーの生成 プライベートキーの保管場所 プライベートキーの管理主体
(鍵更新などの運用)
Cloudflare 管理の証明書
(Universal, Advanced)
Cloudflare Cloudflare 内で完結 Cloudflare
持ち込み証明書
カスタムCSR利用)
Cloudflare Cloudflare 内で完結 Cloudflare
持ち込み証明書 顧客 顧客側で生成したものを Cloudflare にアップロードし、顧客側でも保管 顧客
Keyless SSL 顧客 顧客側で完結 顧客

Keyless SSL 通信フロー詳細

以下のブログで詳細が公開されています。

セッション開始時には以下のような通信となり、Cloudflare からキーサーバーへの通信が発生します。

ハンドシェイクシークエンス図から得られる教訓の1つは、プライベートキーが各ハンドシェイクで一度しか使用されないことです。これにより、TLSハンドシェイクを地理的に分割し、CloudFlareのエッジでほとんどのハンドシェイクを行いながら、プライベートキー操作をリモートキーサーバーに移動することができます。このキーサーバーは顧客のインフラストラクチャに配置されるため、彼らだけがプライベートキーに独占的アクセス権を持つことができます。

cloudflare_keyless_ssl_handshake_rsa

続いて、TLS session resumption の仕組みを使ってセッションの状態を再開する場合の通信フローです。

直近のNewSessionTicketでサーバからクライアントに送り出されたSession Ticketを、今度はClientHelloのSession Ticket拡張のパラメータに詰めてクライアントからサーバへと送ります。
サーバ側ではこれを解読し、有効な内容と認められれば、それを使って「セッション再開」手順によるハンドシェイクを行います。

省略されたハンドシェイク処理によって、キーサーバーへの通信が発生しない形で処理が可能になります。

session_resumption_with_session_ticket

Cloudflare の場合、セッションチケットの有効期限は 18 時間に設定されています。

また、セッションチケットの有効期限ヒントを18時間に設定しました。これはSSLセッションタイムアウトと同じ値です。各サーバーは、過去18時間のチケット復号化のためにチケットキーを保持しています。

以下のコマンドで TLS session ticket lifetime hint: 64800 (seconds) となっていることが確認できます。

% echo Q | openssl s_client -connect www.cloudflare.com:443 -tls1_2 -debug -msg
CONNECTED(00000005)

...

---
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Server public key is 256 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
No ALPN negotiated
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-ECDSA-CHACHA20-POLY1305
    Session-ID: C58FE073B09D73C1D9B1369E8D5902C4B4D88CA0BF686EDFA5B94FCB2D207056
    Session-ID-ctx: 
    Master-Key: FE0C8A5884F1398EB15B1C5578B0373081B6077BD9292E54C7807523617498A0C5970EEF6921A28F729A80CF4DD8A4B4
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    TLS session ticket lifetime hint: 64800 (seconds)
    TLS session ticket:
    0000 - ec d7 3d 0f 69 7d 6d e8-04 69 59 89 61 97 42 28   ..=.i}m..iY.a.B(
    0010 - 8e 2a 11 59 0b 09 93 66-d9 e5 ce 9a 56 59 41 99   .*.Y...f....VYA.
    0020 - 5d 62 2c fc 63 2b 1a 06-f2 f8 04 5e 3a 35 c9 f4   ]b,.c+.....^:5..
    0030 - 21 ef 8e 3f 50 22 ef 44-6f 73 f4 1d e7 ad f3 ee   !..?P".Dos......
    0040 - 40 ae 96 fb d4 3d 31 92-46 15 aa e2 6f 31 b7 5e   @....=1.F...o1.^
    0050 - 64 e6 03 1b f3 d5 68 b6-4d b9 0c 5c 55 ff 41 90   d.....h.M..\U.A.
    0060 - c5 9f 30 3a d9 96 c4 9b-f9 cd f3 a4 24 98 2f 58   ..0:........$./X
    0070 - f8 38 80 25 82 4a 07 44-62 d7 6a 92 8b 80 64 c3   .8.%.J.Db.j...d.
    0080 - 6c be 61 41 52 ae cd ee-06 15 85 80 8a fc 91 bf   l.aAR...........
    0090 - 69 59 0d cf 23 c8 d8 1d-7b 3f 75 be cc e0 97 50   iY..#...{?u....P
    00a0 - 5e 9f ad ea 7d 65 2a 41-cd 3e 49 f6 11 a3 ee ce   ^...}e*A.>I.....
    00b0 - ff e8 96 c6 a4 a6 b3 ac-b8 d9 3c c7 88 aa 1a 5f   ..........<...._

    Start Time: 1682350487
    Timeout   : 7200 (sec)
    Verify return code: 0 (ok)
    Extended master secret: yes
---

...

また、セッションチケットを利用した TLS session resumption の様子も reconnect オプションでの複数回接続試行の結果で Reused  により確認できます。

% echo Q |  openssl s_client -connect www.cloudflare.com:443 -reconnect -tls1_2  | grep -ie New -ie Reuse  
depth=2 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root
verify return:1
depth=1 C = US, O = "Cloudflare, Inc.", CN = Cloudflare Inc ECC CA-3
verify return:1
depth=0 C = US, ST = California, L = San Francisco, O = "Cloudflare, Inc.", CN = www.cloudflare.com
verify return:1
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
DONE
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305

キーサーバーを立てる

こちらの実装を使ってキーサーバーを構築します。

今回は Cloudflare Tunnel を使ったセットアップをします。

img

gokeylesscloudflared インストール

インストール手順は https://pkg.cloudflare.com にあります。

$ lsb_release -a
No LSB modules are available.
Distributor ID:	Debian
Description:	Debian GNU/Linux 11 (bullseye)
Release:	11
Codename:	bullseye

以下のコマンドで gokeylesscloudflared がインストールできます。

# Add cloudflare gpg key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null

# Add this repo to your apt repositories
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com bullseye main' | sudo tee /etc/apt/sources.list.d/cloudflared.list

# install gokeyless
git clone https://github.com/cloudflare/gokeyless.git
cd ~/gokeyless/pkg
sudo cp gokeyless.service /etc/systemd/system/
sudo mkdir -p /etc/keyless
sudo cp keyless_cacert.pem /etc/keyless/
cd ~/gokeyless/pkg/debian/
sudo chmod +x *.sh
sudo ./before-install.sh
sudo apt-get update && sudo apt-get install gokeyless
sudo ./after-install.sh 

# Add this repo to your apt repositories
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared bullseye main' | sudo tee /etc/apt/sources.list.d/cloudflared.list

# install cloudflared
sudo apt-get update && sudo apt-get install cloudflared

Cloudflare Tunnel 設定

次に以下の手順で Cloudflare Tunnel を設定します。

image-20230425011342577

以下の "virtual_network_id""network" パラメータをメモします

export EMAIL='YOUR_EMAIL'
export APIKEY='YOUR_API_KEY'
export ACCOUNT_ID='YOUR_ACCOUNT_ID'

% curl -sX GET "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/teamnet/routes" \
     -H "X-Auth-Email: $EMAIL" \
     -H "X-Auth-Key: $APIKEY" \
     -H "Content-Type: application/json" | jq '.result[] | select (.tunnel_name == "keyless")'
{
  "network": "10.174.0.7/32",
  "tunnel_id": "9b29c9d0-6d03-4e61-ae43-3b30a0cbc339",
  "comment": "",
  "created_at": "2023-04-24T16:13:08.166254Z",
  "deleted_at": null,
  "virtual_network_id": "604aa865-1642-405c-a745-3d448f69b8f1",
  "tunnel_name": "keyless"
}

証明書準備

検証に使う証明書を acme.sh を使って発行します。

sudo apt-get install socat
curl https://get.acme.sh | sh
cd .acme.sh
./acme.sh --issue --dns -d keyless.example.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please \
--force --keylength ec-384 --server letsencrypt
# _acme-challenge TXT レコードを追加後
./acme.sh --renew -d keyless.example.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please \
--force --ecc --server letsencrypt

以下のディレクトリに証明書と鍵のファイルが配置されます。

[Mon Apr 24 16:29:00 UTC 2023] Your cert is in: /home/kyouhei/.acme.sh/keyless.example.com_ecc/keyless.example.com.cer
[Mon Apr 24 16:29:00 UTC 2023] Your cert key is in: /home/kyouhei/.acme.sh/keyless.example.com_ecc/keyless.example.com.key

鍵ファイルは同じものを /etc/keyless/keys に配置します。

sudo mkdir -p /etc/keyless/keys
sudo cp /home/kyouhei/.acme.sh/keyless.example.com_ecc/keyless.example.com.key /etc/keyless/keys/

証明書アップロード

先ほど発行した証明書ファイルを https://dash.cloudflare.com/?to=/:account/:zone/ssl-tls/edge-certificates からアップロードします。

image-20230425143232531

先ほどの "virtual_network_id""network" パラメータを使って以下のように指定します。

image-20230425013407253

キーサーバー設定

gokeyless.yaml を以下のように設定します。

sudo touch /etc/keyless/gokeyless.yaml
cat << EOS | sudo tee /etc/keyless/gokeyless.yaml
# Set the log level (0 = DEBUG, 5 = FATAL).
loglevel: 0

# Hostname must match the key server hostname that was configured in the
# Cloudflare dashboard during custom certificate upload.
hostname: 10.174.0.7

# Zone ID can be found on the Cloudflare dashboard 'Overview' tab.
zone_id: YOUR_ZONE_ID

# Origin CA API Key can be found on the Cloudflare dashboard under the 'My
# Profile' section.
origin_ca_api_key: YOUR_ORIGIN_CA_API_KEY

# Configure one or more private key directories.
private_key_stores:
- dir: /etc/keyless/keys

# Optionally customize the location of the certificates used for mutual
# authentication with Cloudflare keyless clients.
# auth_cert: /etc/keyless/server.pem
# auth_key: /etc/keyless/server-key.pem
# auth_csr: /etc/keyless/server.csr
# cloudflare_ca_cert: /etc/keyless/keyless_cacert.pem

# Optionally customize the listen ports.
port: 2407
metrics_port: 2406

# Optionally write the PID to a file (note that sysv-based systems will
# ignore this value and always use /var/run/gokeyless.pid).
pid_file:
EOS

サービス起動

以下のコマンドでサービスを起動します。

sudo service gokeyless restart

正常に起動したことを確認します。

$ sudo service gokeyless status
● gokeyless.service - gokeyless daemon
     Loaded: loaded (/etc/systemd/system/gokeyless.service; disabled; vendor preset: enabled)
     Active: active (running) since Tue 2023-04-25 05:27:23 UTC; 8min ago
   Main PID: 188376 (gokeyless)
      Tasks: 7 (limit: 4691)
     Memory: 18.2M
        CPU: 88ms
     CGroup: /system.slice/gokeyless.service
             └─188376 /usr/local/bin/gokeyless

Apr 25 05:27:23 kyouhei-osaka-keyless systemd[1]: Started gokeyless daemon.
Apr 25 05:27:23 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 05:27:23 [INFO] loading /etc/keyless/keys/keyless.example.com.key...
Apr 25 05:27:23 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 05:27:23 [DEBUG] add signer with SKI: f39703813ebc2519d214d5731af56b8a95c7fa6b (https://crt.sh/?ski=f39703813ebc2519d214d5731af56>
Apr 25 05:27:23 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 05:27:23 [INFO] Serving metrics endpoint at :2406/metrics
Apr 25 05:27:23 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 05:27:23 [INFO] Listening at tcp://[::]:2407

Keyless SSL 通信の確認

キーサーバーで以下のコマンドを打ち、ログを見ながら通信を確認します。

sudo journalctl -f -u gokeyless

以下のように毎回セッションチケットを発行するような通信では、

% echo Q | openssl s_client -connect keyless.example.com:443 -tls1_2 -debug -msg
...
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
% echo Q | openssl s_client -connect keyless.example.com:443 -tls1_2 -debug -msg
...
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
% echo Q | openssl s_client -connect keyless.example.com:443 -tls1_2 -debug -msg
...
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...

コマンドを実施するごとに fetch key with SKI でキーサーバーへの通信が発生します。

Apr 25 06:19:20 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 06:19:20 [INFO] fetch key with SKI: f39703813ebc2519d214d5731af56b8a95c7fa6b
Apr 25 06:19:21 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 06:19:21 [INFO] fetch key with SKI: f39703813ebc2519d214d5731af56b8a95c7fa6b
Apr 25 06:19:22 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 06:19:22 [INFO] fetch key with SKI: f39703813ebc2519d214d5731af56b8a95c7fa6b

次にセッションチケットを利用してハンドシェイクが省略されているかどうかを確認するために reconnect オプションで何度か接続を試みます。

新規接続(New)からセッション再利用(Reuse)の出力を確認できますが、

% openssl s_client -reconnect -host keyless.example.com -port 443
...
New, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
Reused, TLSv1.2, Cipher is ECDHE-ECDSA-CHACHA20-POLY1305
...
closed
...

キーサーバーのログから確認できた fetch key with SKI は1度だけでした。

これで省略されたハンドシェイク処理によって、キーサーバーへの通信が発生しない形で処理されていることを確認できました。

Apr 25 06:18:23 kyouhei-osaka-keyless gokeyless[188376]: 2023/04/25 06:18:23 [INFO] fetch key with SKI: f39703813ebc2519d214d5731af56b8a95c7fa6b

感想

Cloudflare のようなエッジサービスを使いながらも、プライベートキー(秘密鍵)は外部に出さない運用ができることがわかりました。

キーサーバーもステートレスに増やしていけるため、柔軟に構成が可能です。

Hardware Security Module (HSM) でプライベートキー(秘密鍵)運用をされている場合は、その要件を満たすことができ、設定も容易です。

2023年3月にサポートされた、Keyless SSL と Cloudflare Tunnel の構成を確認でき、よく理解できました。

プライベートキー(秘密鍵)をセキュアに利用させる構成としては、非常に簡単に始められると思います。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?