ここ数ヵ月、多くの方が当社のDiscord サーバーを訪れて、Zenohは、 TLSを通信トランスポートと使用した場合にLetsEncryptと互換性があるかどうかを質問されました。つまり、どうやってLetsEncryptをZenohで使うかということです。
このブログ投稿では、それが実は可能であることをお見せし、セットアップする時に必要なすべてのステップをご説明します。もし、すでにTransport Layer Security やLetsEncryptについてご存じなら、この説明はスキップしてすぐにチュートリアルを始めましょう。
Transport Layer Security(TLS)
LetsEncryptについて始める前に、Transport Layer Security(TLS)についてご存じでない読者のために少し紹介しておきます。TLSは、インターネット上(またはあらゆるタイプのIPベースのネットワーク)での通信のセキュリティとプライバシーを提供するために設計されている暗号プロトコルです。これは、情報の送信をセキュアに行うために2つのピア間で暗号化された接続を確立するのに使用されます。たとえば、HTTPSプロトコルによる接続をセキュアに行うために広く使用されています。
ZenohはTLSとmTLS(相互TLS)の両方を通信トランスポートとしてサポート します。
TLSをZenoh上で設定するには当社文書をご覧ください。Zenohの設定をセットアップして、MiniCAという名前のツールからの一般化キーと認証を使用する方法を説明します。MiniCAは、「認証が使用される各ホストをCAオペレーターも操作する状況での使用を意図した小さくてシンプルなCAです」
認証局とは(CA)?
認証局(CA)には、TLSの運用において(i) メッセージの送信元 / 受信先のアイデンティティを検証することと、(ii) 送信元と受信先の間のメッセージの暗号化 / 復号化する(つまり、エンティティをその公開鍵に関連付ける)手段を提供することの2つの役割があります。
クライアントがサーバーへのセキュアな接続をリクエストした場合、サーバーはデジタル証明をクライアントに提示することで応答します。この証明は、クライアントとの暗号化された接続を確立するために使用されるサーバーの公開鍵を含む、サーバーのアイデンティティについての情報を含みます。
サーバーのデジタル証明の認証と完全性を確実にするために、信用のおける第三者CA(例えば、独自の手段で証明書を扱う場合は、MiniCA)により署名されていなければなりません。これにより、TLS プロトコルの信用とセキュリティが確立されます。
現在では、サーバーの完全性を検証するのに使用される信用された第三者認証局はいくつかあります。その多くは、ウェブ公開鍵インフラストラクチャ(Web PKI)として知られているもので、ウェブブラウザとほかのアプリケーションが必要とする証明書を発行する信頼できるチェーンを認証局が形成するシステムです。HTTPSを介したセキュア接続の確立時に、クライアントアプリケーションは、証明チェーンを確認し、証明が信用されているCAにより発行され、無効にされていたり、期限切れになったりしていないかを確認します。もし証明が有効で信用できるものなら、ブラウザまたはクライアントアプリケーションは、そのサーバーと暗号化された接続を確立します。
LetsEncrypt は、無料で自動のオープン認証局(WebPKIの一部)で、ウェブサイト上でHTTPS(SSL/TLS)暗号化することを可能にするデジタル証明を提供するものです。LetsEncryptは、2015年に、Internet Security Research Group(ISRG)により立ち上げされたもので、ウェブサイトオーナーがそのサイトをSSL/TLS証明により簡単にセキュアにできるようにすることを目的とし、今日では、Web PKI エコシステムの一員となっています。Let’s Encrypt は、ウェブサイトオーナーのコスト負担なく、発行、更新、管理が自動的に行われるデジタル証明を提供するという特性を有します。これにより、SSL/TLS証明書を取得し、管理する上でのコストや技術的複雑性をなくし、ウェブオーナーが自分のトラフィックを簡単に暗号化し、ユーザのプライバシーを保護できるようにします。
Zenohを備えるLetsEncryptの使い方
WebPKIの認証局をロードすることは、TLS通信をroot_ca_certificate fieldを特定せずにセットアップする場合は、Zenohのデフォルト動作です。しかし、認証局が静的なIPアドレスに結び付けられた証明書を提供するのは非常に稀なので、DNSを有するパブリックサーバー上でZenoh routerをホストすることを必要とします。
次のステップは、LetsEncrypt 証明書の取得です。そのためには、当社のサーバー内の チャレンジのひとつを解決する必要があります。ここでは、LetsEncrypt 文書で説明しているようにHTTP-01 チャレンジを使用します:
これは、今日の最も一般的なチャレンジタイプです。Let’s Encryptは、お客様の ACMEクライアントにトークンを与え、お客様のACME クライアントは、以下のアドレスのお客様のウェブサーバーにファイルを置きますhttp://<YOUR_DOMAIN>/.well-known/acme-challenge/<TOKEN>.このファイルはトークンと、お客様のアカウントキーのサムプリントを含んでいます。お客様のACMEクライアントが、Let’s Encryptに、ファイルの準備ができていることを告げると、Let’s Encryptは、それを読み出すことを試します(複数のバンテージポイントから複数回の場合もあります)当社の認証チェックがお客様のウェブサーバーから正しい応答を得た場合、認証は成功したとされ、お客様は自分の証明書を発行することができます。もし認証チェックに失敗した場合は、新しい証明書で再びトライしなければなりません。
「Let’s Encrypt クライアントとGoに記載されたACMEライブラリ」であるLegoを使えば、このチャレンジとよりシンプルに取り組むことができます。Legoは、それを読み出すためのLetsEncrypt用のacme チャレンジトークンを保存する目的だけのために一時的なウェブサーバーをセットアップします。
router.zenoh.io.にホストされたルータがあると仮定します。Lego 文書で説明したように、以下のコマンドを実行する必要があります。
lego --email="your@email.com" --domains="router.zenoh.io" --http run
お客様が適切な設定をしないかぎりsudoで実行する必要があるかもしれません。また、LetsEncryptがACMEトークンの読み出しが可能となるには、当社のサーバーのポート80と443が必要です。
その後、lego ディレクトリで(ディレクトリはデフォルトでは隠されています)LetsEncrypt証明を取得する必要があります:
$ ls ~/.lego
router.zenoh.io.crt
router.zenoh.io.issuer.crt
router.zenoh.io.json
router.zenoh.io.key
それを得たなら、当社の設定では、このTLS接続をセットアップする際には、router.zenoh.io.crtとrouter.zenoh.io.key.を使います。
{
mode: "router",
listen: {
endpoints: ["tls/[::]:7447"],
},
transport: {
link: {
tls: {
// The root_ca_certificate field is disabled
server_private_key: "router.zenoh.io.key",
server_certificate: "router.zenoh.io.crt",
},
},
},
}
なお、the root_ca_certificate fieldは特定していないことをご留意ください。これは(すでに述べたように)、このケースのデフォルトの動作はWebPKI 証明のロードだからです。
これで、TLSでZenohルータを実行して、LetsEncrypt証明をロードするようにすべて設定できました。例えば、Zenohの例 を設定してみて、うまくいくかどうか見てみましょう!
ルータをスタートさせましょう。サーバー端末で以下を実行してください:
./zenohd -c config.json5
config.json5 が上記の設定の場合
これで、パブリッシャーとサブスクライバーを実行して、トラフィックがルータを流れるか見てみましょう。
パブリッシャーを実行
./z_pub -m client -e tls/router.zenoh.io:7447
次のようになるはずです:
Opening session...
Declaring Publisher on 'demo/example/zenoh-rs-pub'...
Putting Data ('demo/example/zenoh-rs-pub': '[ 0] Pub from Rust!')...
Putting Data ('demo/example/zenoh-rs-pub': '[ 1] Pub from Rust!')...
Putting Data ('demo/example/zenoh-rs-pub': '[ 2] Pub from Rust!')...
Putting Data ('demo/example/zenoh-rs-pub': '[ 3] Pub from Rust!')...
Putting Data ('demo/example/zenoh-rs-pub': '[ 4] Pub from Rust!')...
Putting Data ('demo/example/zenoh-rs-pub': '[ 5] Pub from Rust!')...
そして、サブスクライバーは:
Opening session...
Declaring Subscriber on 'demo/example/**'...
Enter 'q' to quit...
>> [Subscriber] Received PUT ('demo/example/zenoh-rs-pub': '[ 0] Pub from Rust!')
>> [Subscriber] Received PUT ('demo/example/zenoh-rs-pub': '[ 1] Pub from Rust!')
>> [Subscriber] Received PUT ('demo/example/zenoh-rs-pub': '[ 2] Pub from Rust!')
>> [Subscriber] Received PUT ('demo/example/zenoh-rs-pub': '[ 3] Pub from Rust!')
>> [Subscriber] Received PUT ('demo/example/zenoh-rs-pub': '[ 4] Pub from Rust!')
>> [Subscriber] Received PUT ('demo/example/zenoh-rs-pub': '[ 5] Pub from Rust!')
できました!
デバッグモードのログを見るのは興味深いものです(例えば、RUST_LOG=debug ./z_pub -m client -e tls/router.zenoh.io:7447)。確立したTLS通信も見れるでしょう。
[2023-03-24T10:24:33Z DEBUG zenoh_link_tls::unicast] Field 'root_ca_certificate' not specified. Loading default Web PKI certificates instead.
[2023-03-24T10:24:33Z DEBUG rustls::client::hs] No cached session for DnsName(DnsName(DnsName("router.zenoh.io")))
[2023-03-24T10:24:33Z DEBUG rustls::client::hs] Not resuming any session
[2023-03-24T10:24:33Z DEBUG rustls::client::hs] Using ciphersuite TLS13_AES_256_GCM_SHA384
[2023-03-24T10:24:33Z DEBUG rustls::client::tls13] Not resuming
[2023-03-24T10:24:33Z DEBUG rustls::client::tls13] TLS1.3 encrypted extensions: [ServerNameAck]
[2023-03-24T10:24:33Z DEBUG rustls::client::hs] ALPN protocol is None
[2023-03-24T10:24:33Z DEBUG rustls::client::tls13] Ticket saved
...
つまり、ルータのアイデンティティをWebPKI(そしてLetsEncrypt)が認証したということです。
結論
TLS on Zenoh LetsEncrypt 証明書を有する Zenohを装備したTLSを使った当社の通信をどのようにセキュアにするかをこれまで説明してきました。Zenohを使ってTLS通信をどのように設定するかについての詳細は、本文書をご覧ください。当社のDiscord コミュニティに是非参加して、質問してください。
1. RAWによる githubusercontent.com/letsencrypt/website/master/static/images/letsencrypt-logo-horizontal.svg, Fair Use, https://en.wikipedia.org/w/index.php?curid=47031340