A Kubernetes engineer’s guide to mTLS
#翻訳
原文: https://buoyant.io/mtls-guide/
Introduction
相互TLS(mTLS)は、Kubernetesの世界でホットなトピックです。特に、アプリケーションの「転送中の暗号化」を取得する必要がある人にとってはなおさらです。 しかし、mTLSとは何ですか、どのような種類のセキュリティを提供しますか、そしてなぜそれが必要なのですか?
このガイドでは、これらの質問に答えるために最善を尽くします。 mTLSとは何か、「通常の」TLSとどのように関連するか、Kubernetesに関連する理由について説明します。 また、mTLSとその代替の長所と短所のいくつかについても説明します。 最後に、Linkerdを使用してKubernetesクラスターにmTLSを追加する方法を説明します。
始める前の注意点:私は基本的に、mTLSを実用的なレベルで理解している平凡なKubernetes対応のエンジニアです。 このガイドでは、正確で微妙な違いを認識したときに指摘するように最善を尽くしましたが、これはセキュリティの観点からのmTLSの詳細な分析ではなく、そのようなものを書く資格もありません。 訂正と説明は大歓迎です。Twitterで私に連絡するか、私の名@ buoyant.ioにメールを送ってください。
What is mTLS?
mTLSは、クライアントも認証されるという1つの追加規定を備えた単純な「通常のTLS」です。 しかし、それはどういう意味で、なぜそれが必要なのですか?
これらの質問に答える前に、TLSの基本的な理解から始める必要があります。 TLSは、TCP接続にセキュリティを提供するように設計された接続レベルのプロトコルです(セキュリティの意味については、以下で詳しく説明します)。 TLSは接続レベルで機能するため、アプリケーションレベルのTCPプロトコルと組み合わせることができ、そのプロトコルは何も変更する必要がありません。 たとえば、HTTPSはTLSと組み合わせたHTTPであり(HTTPSの「S」はTLSの前身であるSSLを指します)、TLSに対応するためにHTTPについて何も変更する必要はありません。
あなたがセキュリティの専門家である場合、そして私が間違いなく1人ではないことを再度指摘しますが、TLSとは「複雑な」関係にある可能性があります。 TLSには、セキュリティの観点から最適ではない、あらゆる種類の問題と癖があります。 仕様は複雑で指定が不十分であり、実際には意味をなさないビットがあり、実装はとにかく仕様に100%準拠することはありません。
これらの懸念にもかかわらず、TLSはいたるところにあります。あなたは現在TLSを使用しています。このページはHTTPS経由で提供されており、ブラウザのURLバーに小さな鍵のアイコンが表示され、クリックすると落ち着かせる言葉が表示されます。
What kind of security does TLS provide?
ほとんどの人はTLSを暗号化と関連付けています。 しかし、TLSはそれだけではありません。 TLSは、接続に対して3つの保証を提供します。
信憑性:どちらの側の当事者も、自分が本人であると証明できます。
機密性:他の誰も、どんなデータが交換されているかを見ることができません。
整合性:受信したデータは、送信したデータと同じです。
したがって、TLSは暗号化を提供しますが(これにより機密性が実現されます)、TLSの観点からは、安全な通信には不十分です。3つのプロパティすべてが必要です。 あなたが信憑性を持っていない場合、誰かが接続の反対側にいることを偽装する可能性があります。 整合性がない場合、誰かが通信の重要な部分を変更する可能性があります。 そして、あなたが守秘義務を持っていないなら、誰でも聞くことができます。
これらの3つの保証の中で、この議論で最も興味深いのは信頼性です。 このガイドの残りの部分では、信頼性と認証について多くのことを話します。
When is mTLS useful?
元の定義に戻ります。mTLSは単に「通常のTLS」であり、クライアントも認証されるという追加の規定があります。 TLSの基本を理解したので、このステートメントを解析できます。 TLSは信頼性を保証しますが、デフォルトでは、これは一方向でのみ発生します。クライアントはサーバーを認証しますが、サーバーはクライアントを認証しません。 mTLSは信頼性を対称にします。
TLSのデフォルトが一方向でのみ認証されるのはなぜですか? 多くの場合、クライアントのIDは無関係だからです。 たとえば、このページをロードする際に、ブラウザはbuoyant.ioが本人であると主張していることを検証しましたが、buoyant.ioはブラウザのIDを検証していません。 それは実際にはあなたのブラウザのアイデンティティを気にしません。 (率直に言って、buoyant.ioはあなたがこの記事を読んでいることを嬉しく思います。)
もちろん、クライアントIDを検証しないことは、Webページを提供するのに意味がありますが、クライアントのIDが重要な通信にはさまざまな種類があります。 API呼び出しはその一例です。Twilioのようなサービスを呼び出す場合、Twilioは、請求書を送信できるように、他の理由の中でも、あなたが誰であるかを知る必要があります。 何らかのクライアントIDを提供せずにTwilio API呼び出しを行うことはできません。
ただし、TwilioはmTLSを使用しません。 代わりに、アカウントの作成時に割り当てられた秘密の「認証トークン」をTwilioに与えることで、Twilioに対して自分自身を認証します。 TwilioはmTLSを使用できますが、mTLSは複雑で、セットアップが面倒です(これについては後で詳しく説明します)。したがって、TwilioのようなパブリックAPIを提供する場合は、おそらく認証トークンを使用するだけです。
ただし、mTLSを使用した認証には、認証トークンアプローチにはない非常に強力な特性がいくつかあります。 1つは、IDを作成、登録、または管理するためのアプリレベルの機能を必要とせずに、mTLS認証を完全にアプリケーションの外部で実行できることです。 最初のTwilio呼び出しを行う前に、Webサイトにログインし、アカウントを作成して、トークンを取得する必要があります。TwilioAPIは、この認証トークンを認識し、API呼び出しに渡して管理する方法を提供する必要があります。しかし、mTLSを使用すると、まったく新しいクライアントは、これまで誰も見たことがなくても、すぐに自分自身を認証できます。 また、アプリケーションは認証について何も知る必要がなく、認証を管理するためのエンドポイントを提供する必要もありません。
これらすべてをまとめると、mTLSは次のような状況に最適であることがわかります。a)安全な通信が必要。 b)クライアントのアイデンティティを気にする。 c)IDを管理するためのアプリレベルのフローを構築したくない。 また、実際問題、d)mTLSは、実際に実装する複雑さを管理できる状況に最適です。
これらすべての特性を備えた1つの状況は、…マイクロサービスです。
Using mTLS to secure microservices
mTLSは、上記で概説したすべての理由から、マイクロサービス間のサービス間通信を保護するための優れた方法です。
まず、安全な通信が必要です。 アプリケーションを複数のサービスとして実装すると、これらのサービス間のネットワークを介して機密性の高い顧客データを送信することになります。 ネットワークにアクセスできる人は誰でも、この機密データを読み取ってリクエストを偽造できる可能性があります。
第二に、あなたはクライアントのアイデンティティを気にします。 1つは、診断目的で通話がいつ発信されたかを確認し、メトリックなどが適切に記録されるようにする必要があります。 さらに、おそらくこれらのIDで承認を行いたいと思うでしょう(BはAに電話することさえ許可されていますか?)。 承認については後で詳しく説明します。
第三に、サービスIDを管理するためのアプリレベルのフローを実際に構築する必要はありません。 それはビジネスロジックではなく、開発者の時間は他の場所で費やしたほうがよいでしょう。
最後に、プラットフォームを制御すれば、mTLSの実装の複雑さを実際に管理できます。 または、少なくとも、Twilioよりも優れています。 Twilioの例では、すべてのユーザーがTwilioに対して自分自身を認証するという課題を解決する必要があります。 その課題が難しいほど、ユーザーにとっては悪化します(そして、Twilioの収益にとっても悪化します)。 ただし、プラットフォームレベルでmTLSを実装できる場合は、サービスごとまたはユーザーごとではなく、一度だけコストを支払います。
要約すると、mTLSはマイクロサービス間の通信を保護するのに最適です。 しかし、落とし穴があります。
The hard part of TLS: certificate management
これまで、mTLSのバラ色の絵を描きました。 クライアントとサーバーはお互いに陽気に認証し、セキュリティが発生します。 実際には、mTLSを機能させる上での大きな実際的な課題は、証明書の管理です。
TLSでの認証は、公開鍵暗号化と公開鍵インフラストラクチャを介して機能します。 これらは両方ともそれ自体が途方もないトピックであり、この記事では詳細には触れません。 しかし、要するに、それらは非常に多くの証明書を含みます。
TLS認証は、X.509証明書という楽しい名前の何かに基づいています。 X.509証明書には、特にアイデンティティと公開鍵が含まれています。 公開鍵には、証明書の一部ではない対応する秘密鍵もあります。 TLSで自分自身を認証する前半は、証明書を反対側に表示し、秘密鍵を使用して証明書内のIDが自分のものであることを証明することです。 (公開鍵暗号化の魔法は、証明書をコピーする人は秘密鍵を持っていないため、この証明を行うことができないことです。したがって、平文チャネルを介して送信したり、証明書をオープンに保存したりするなど、証明書を自由に使用できます。)
X.509証明書は、認証局(CA)によって署名されており、CAがその証明書のIDを「信頼」していることを示しています。 これはTLS認証の後半に使用されます。誰かが自分のIDを表示し、それを所有していることを証明した場合、そのIDを信頼するかどうかを決定する必要があります。 TLSはここで単純なルールを使用します。証明書がCAによって署名されており、そのCAを信頼する場合は、IDも信頼します。 CAの証明書の署名をどのように確認しますか? CA自体のX.509証明書を使用することにより確認します。 そのCAを信頼しているかどうかはどうやってわかりますか? 基本的に、TLSプロトコル以外の方法でそれを信頼するように言われています。
CAは証明書も発行します。 証明書を取得するには、最初に公開鍵と秘密鍵のペアを作成します。 秘密鍵を秘密にしておくと(ネットワーク経由で送信されることはありません)、公開鍵とIDを含む証明書署名要求(CSR)をCAに送信します。 CAが要求を承認すると、証明書が作成され、署名されて、返送されます。
したがって、証明書の管理は、これらすべての証明書を作成して配布するという課題です。 CAが存在すること、すべてのサービスに証明書があること、すべてのサービスがCSRを送信できること、およびCAが証明書をサービスに送り返すことができることを確認する必要があります。 また、CAが安全であること、各サービスの秘密鍵に誰もアクセスできないこと、すべてのサービスが変更できない方法で独自のIDを知っていることを確認する必要があります。
この証明書配布の課題は、Kubernetesのような環境では、「サービス」は実際には、その場で作成または破棄できる、常に変更されるレプリカのセットであり、それぞれに独自の証明書のセットが必要であるという事実によって悪化します。
そしてそれは、実際には、証明書の損失を軽減するために誰もが見つけた最善の方法(つまり、許可されていない誰かが秘密鍵にアクセスしたときに何が起こるか)が証明書のローテーションによるものであるという事実によってさらに複雑になります。証明書の有効期間を非常に短くし、有効期限が切れる前に再発行します。これは、レプリカごとに、n時間ごとにCSRと証明書のフロー全体を繰り返す必要があることを意味します。
さらに、クラスター間で安全な通信を拡張する場合は、一方のクラスターで生成されたIDをもう一方のクラスターで使用できるようにする方法が必要ですが、クラスター全体が危険にさらされた場合はさらに複雑になります。 、他のすべてのクラスターを無効にすることなく無効にすることができます。 これは、ご想像のとおり、より多くの証明書を使用して行います。
要約すると、mTLSを実行するには、常に非常に多くの証明書が必要です。 この課題の複雑さは気が遠くなる可能性があります。 しかし、それにもかかわらず、mTLSはKubernetesの世界でルネッサンスのようなものを見てきました。 これは、KubernetesがmTLSを実現可能にする特定のタイプのテクノロジーであるサービスメッシュのロックを解除するためです。
Kubernetes, mTLS, and the service mesh
サービスメッシュは、クラスターにmTLSを追加するための驚くほど優れたメカニズムです。 どうして? Linkerdのようなものが実際にあなたのためにすべての仕事をすることができるからです。 証明書管理の課題だけでなく、TLS接続の確立と受信自体も処理できます。 Linkerdは、「クラスターへのmTLSの追加」をゼロ構成操作にします。LinkerdをKubernetesクラスターにインストールすると、メッシュポッド間のすべての通信が自動的にmTLSになります。 mTLSのように複雑なものの場合、それは非常に素晴らしいことです。
Kubernetesは、サイドカーの展開など、他の方法では非常に複雑になるものを扱いやすくするため、これはすべて可能です。 Kubernetesの魔法のおかげで、Linkerdは次のことができます。
「マイクロプロキシ」を各アプリケーションポッドに透過的に挿入し、このプロキシを介してポッドとの間ですべてのTCP通信をルーティングします。
TLS証明書を発行できるコントロールプレーンの一部として内部CAを出荷し、このCAの証明書をすべてのプロキシに安全に配布します。
このCAを使用して、ポッドのKubernetes ServiceAccount IDに関連付けられた、短期間の証明書を各プロキシに発行します。
これらの証明書をn時間ごとに再発行します。
各プロキシに、これらの証明書を使用してポッドへのすべての接続にmTLSを適用させ、クライアントとサーバーが両側で有効なIDを持っていることを保証します。
接続がアプリケーションに到達する前に、これらのIDを使用して承認ポリシーを適用します。
もちろん、これはすべて単純化したものです。 たとえば、Linkerdは、クラスター間の通信を可能にするために、実際には2つのレベルのCAを使用します。1つはクラスターレベルで、もう1つはグローバルレベルです。 また、Linkerdは複数の信頼ルートを使用できるため、CAをローテーションすることもできます。 等々。
しかし、これらの詳細について心配する必要はありません。 Linkerdをインストールし、ポッドをメッシュして、出来上がりです。mTLSがあります。
これは、Linkerd 2.3の初期に作成した75秒のビデオで、mTLSの前後にtsharkを使用してGKEクラスター上のパケットをスニッフィングする様子を示しています。
https://www.youtube.com/watch?v=ctQTgEKfHaE
きちんとしていますよね? それでは、これを自分で設定するのがいかに簡単かを正確に見てみましょう。
Tutorial time
省略
#Linkerd #ServiceMesh