ぼちぼち日記

おそらくプロトコルネタを書いていることが多いんじゃないかと思います。

RPCに特化したGoogleのセキュリティ通信ALTSとは何か

はじめに

昨年、Googleから Google Cloud Platform に関するWhitePaperがいくつか公開されました。その中でGoogleのサービス内部で使われている新しいALTSというプロトコルを説明した文書「Application Layer Transport Security」は、読んでみると非常に面白く、セキュアなサービス間通信には本当に何が必要なのか、といったことを改めて深く考えさせられるものでした。物理的なマシンからサービス運用まで、ALTSがカバーする範囲は幅広い領域に渡り、あの巨大なGoogleのサービスをよくここまでまとめ上げたものだとホント感心させられます。

以前から、Googleはデータセンタ内のサービス通信までも暗号化を進めていると言われていました。それは、2013年にエドワード・スノーデンが暴露した資料が、Googleのデータセンタ内部の通信データがNSAによって盗聴されていることをうかがわせるものだったからです(「NSA、グーグルと米ヤフーのクラウドに「思いのまま」アクセスか--米報道」)。

一方、Googleのサービス内通信では、RPC(当時はStubby、後のgRPC)が使われていることはよく知られていました。Googleがサービス内通信の暗号化を進めると聞いても、おそらくRPC over TLSを使うようになったんだろうなぁ、と漠然と想像するだけでした。しかし蓋を開けてみると、GoogleはRPCに特化したALTSプロトコルを独自に開発し、それを全面的に利用していたのでした。しかも幅広いレイヤーの認証を実現する独自PKIシステムと共に... ホント驚きです。

Googleが10年かけてフルスクラッチで作り上げてきたALTSとは、いったいどんなものなのか?詳細はまだ公開されていませんが、WhitePaperから読み取れるALTSの姿を書いてみたいと思います。

Disclaimer

本記事は、公開されている資料から筆者が読み取った内容を記載しています。ALTSの詳細な仕様や実装はまだ公開されていません。筆者の想定違いや読み間違いの部分もあるでしょう。筆者は、Google社とは一切関係なく、元社員や現社員からの情報も持ち合わせていません。従いまして、本記事の内容は、一切保証されませんので、お読みになる際はご注意下さい。

Google サービスのネットワーク構成

まずは、Googleサービスのネットワーク構成を見てみましょう。「Encryption in Transit in Google Cloud」のWhitePaperにその概要が記載されています。また、そこに書かれていないGoogleデータセンター外部(各ISPに張り出しているところ)について、QUICの論文「The QUIC Transport Protocol: Design and Internet-Scale Deployment」に少し記載されており、そちらも参考になります。

これらの情報を合わせて、今回関係ある部分だけを抜き出すと、以下のネットワーク構成のようになっていると思われます。 f:id:jovi0608:20180116020131p:plain エンドユーザのクライアントからの接続は、各ISP内に設置してあるREL(restriced edge location)を通ります。Googleドメイン宛の接続の多くは、まずRELでTCPハンドシェイクの終端をして、その後のTLSのハンドシェイクをGFE(Google Front End)で行うといった2段構成になっています。

UDP通信のQUICは、REL上のUDP Proxyを経由して、GFEで直接ハンドシェイクを行います。論文によると、2016年7月にUDP ProxyによるQUIC接続に構成を変えたところ、検索サービスのレイテンシが4%から7%以上も向上し、TCPを上回る性能改善だったと報告されています。WhitePaperには、GFEがTCPの終端も行うことも記載されているので、全てのクライアントがRELを通るわけではなく、クライアントから直接GFEに接続する構成も存在しているものと思われます。

TLSとQUICの終端を担うGFEでは、DDoS防御の後にバックエンドのサービスへ負荷分散やルーティングを行います。図では、GFEからGCE(Google Compute Engine)のVM(Virtual Machine)、もしくはGoogle Cloud Serviceの2つにルーティングされています。

GFEから Google Cloud Serviceへの通信は、今回の主題であるALTS(Application Layer Transport Security)が使われています。ALTSは、アプリケーション層(Layer 7)で行うRPCの暗号化、双方向認証、完全性の確保を実現するセキュリティ通信で、GFEとGoogle Cloud serviceの間、もしくはGoogle Cloud service間の通信でALTSが使われています。

ALTSは、暗号通信とメッセージ認証だけ行う平文通信の2種類をサポートしています。Googleのデータセンタ間をつなぐWANを経由する場合、ALTS通信は暗号化通信ですが、Googleが管理しているデータセンタ内では、暗号化されずメッセージ認証だけの通信が行われます。これらは全て自動で判断されます。

もう一方のGFEからGCE VM宛の通信では、Google Cloud's virtual network authenticationによるLayer3の認証が行われています。この仕組みの詳細は公開されていませんが、(SDNの?)Control Planeにおいて、送信元がSecurity Tokenを付与し、受信側のホストでそのTokenの検証を行って認証を実現していると記載されています。 f:id:jovi0608:20180116020142p:plain Security Tokenは、Token KeyとHost Secretの2つから生成されています。Token Keyは、senderの物理IP 、VMのネットワークID、仮想VMの送信IPを合わせたもの、Host Secretは受信ホストの物理IPとControl Plain間で共有するPhysical boundary secretを合わせたものから作成します。Physical boundary secretは、2時間毎にControl Plane間で再ネゴシエーションして更新されます。このSecurity Tokenによって送信ホストを認証し、IP Spoofingなどに対する防御を実現しています。

ALTSの特徴

ALTSは、2007年よりGoogle内部で開発が始まりました。当時TLSはそれほどセキュアではなく(TLS1.2は2008年仕様化)、TLSの機能も十分でなかったため、Googleのサービス要件に合わせるためにスクラッチからサービス間通信のプロトコルを開発する道を選んだようです。

TLSで不十分な点は、サーバ名といった名前とその命名スキームに強く機能が結びついてしまうことでした。それに対しALTSでは、複数の名前スキームが使えるようにして、マイクロサービスに適した柔軟性と簡潔性を実現しました。TLSで使うX.509証明書は、ASN.1エンコードでしたが、ALTSではハンドシェイクメッセージや証明書のシリアライズにProtocol Buffer形式を採用しました。Protocol Bufferは、Googleサービス内部で多く使われています。

ALTSの柔軟性は、ホスト名ではなくidentityをベースに認証を行うことにあります。このidentityは、従業員、物理マシン、プロダクションサービス、アプリ実行するWorkload等、ネットワーク上のあらゆるレイヤーのもの全てに割り当てを行い、通信の相互認証を可能としました。しかも、Googleは独自内部PKIシステムも構築しました。内部CAからこれらのidentityにALTS用の証明書をほぼ自動で配布し、初期化時に使えるようにセットアップし、頻繁に証明書の更新や失効操作も自動で行っています。いやはや、これすごいです。

他にもALTSの特徴として、以下の項目が挙げられます。

  • アプリ的には全く透過。開発者はALTSを意識しなくていい。
  • サーバ・クライアント双方でセッション再接続(resumption)が可能で、複数のサーバ・クライアント間でセッション引き継ぎができる。
  • アップデートで最新の暗号方式の導入やプロトコルのバージョンアップなどが容易にできる。

ALTSのトラストモデル

ALTSのすごいことの一つに、物理ホストからアプリ・運用開発者まで含めたトラストモデルを構築していることにあります。ここでは、そのトラストモデルの仕組みについて書きます。

ALTS証明書の種類と役割

ALTSのトラストモデルは、Signing Serviceと Master Certificate、Handshake Certificateの3つのレベルの証明書で構成されています。 Signing Serviceは、root CAを持つ認証局のようなもので、その詳細は不明です。ALTSの証明書は、Singing ServiceからMaster証明書、Handshake証明書へchainがつながり、Handshake証明書が、実際のALTSハンドシェイクで利用されるものです。 f:id:jovi0608:20180116020150p:plain 証明書はidentityベースで発行されます。ALTS証明書発行の特徴として、signer(署名者)とissuer(発行者)の役割が別れていることです。

Master証明書が、Handshake証明書を発行する際、まずSigning ServiceにCSRを送ります。Signing Serviceは、CSRにあるissuerとidentityの関係を署名します。Master証明書は、それにALTSハンドシェイクに必要なパラメータ(ECDH公開鍵、暗号方式、失効IDなど)を付与し、自身の証明書も含めてHandshake証明書を署名・発行します。ALTS証明書は、TLSで使われているX.509証明書と全く異なる内容になっています。

さらにALTSの証明書は、発行するidentityの対象によってHuman, Machine, Workloadの3種類に別れています。それぞれGoogle従業員向け、ホスト向け、アプリ向けの証明書を表します。

Human Certificate

Human証明書は、Google従業員がRPCを使う際に利用する証明書です。Googleの内部CAでユーザ名、パスワード、2FAで認証が通ると、申請者のidentityを持つ20時間有効なHuman Handshake証明書が発行されます。接続先のホストには、あらかじめATLS Policyが配布されており、ATLSハンドシェイク中に証明書のissuerやidentityに応じてアクセス許可が判断されます。 f:id:jovi0608:20180116020158p:plain もし、Google従業員の1人が、どこかのMaster証明書からNetwork Adminなど不正な権限を持つHuman Handshake証明書を発行したとしても、このATLS Policyでissuerやidentityをチェックしており、不正な権限によるALTS接続を拒否するようになっています。

Machine Certificate

Googleのデータセンターに設置されている全てのプロダクション機器は、Machine Master証明書を持っています。Machine Master証明書は、マシン管理デーモンなどのコアアプリを使うため、Machine Handshake証明書を生成します。Machine Handshake証明書のidentityは用途によって別けられており、一つのマシンは異なる複数のidentityを持つことができます。 f:id:jovi0608:20180116020212p:plain Machine Master証明書は、検証されたソフトウェアスタック上でのみ利用でき、一部では物理サーバに付随しているTitanと呼ばれるセキュリティチップからMachine Master証明書の署名検証を行う構成も存在しているとのことです。

Workload Certificate

Workload証明書は、Googleで使われているクラスタ管理システムBorgと連携してアプリケーション間のRPC通信で利用します。このWorkload証明書が、アプリケーションによるサービス間のセキュア通信を実現する証明書です。 f:id:jovi0608:20180116020218p:plain Borgの構成では、BorgmasterがBorgletを通じてアプリケーションを実行するWorkloadを作成します。最初にBorgmasterでは、ALTSdというデーモンによってMachine Master証明書からBorgmasterのHandshake証明書を生成します。これによって、BorgmasterはALTS通信が可能となります。

次にBorkmasterは、Sining Serviceから署名されたBase Workload Master証明書を生成します。これがアプ リケーションに必要なWorkload Handshake証明書を作成・管理します。Borglet経由してWorkload Hnadshake証明書と秘密鍵のペアがBorg Workloadマシンに送付されると、Workloadのアプリは実行時にALTS通信が使えるようになります。これら一連の流れが、Borgの仕組みと連動して実現されています。

証明書の失効と更新

ALTSでは、ハンドシェイク時に一時共有鍵を生成するForward Secrecyを利用していません(機能はサポートされていますが無効化されています)。その代わり、証明書に記載された固定の鍵情報を用いた鍵交換を行います。その際、証明書を頻繁に更新し、同一の鍵を長期に使わないようにしてリスク回避をしています。そのため、証明書の更新期間は非常に短く、以下のように種類によって異なっています。全て自動化されているからできる技です。 f:id:jovi0608:20180116020224p:plain ALTSでは、Human証明書だけ明示的な有効期限を持っています(20時間)。それ以外は、時刻同期の問題によって失効機能の障害が発生するのを避けるため有効期限を記載せず、CRL(証明書失効リスト)を使って直接失効管理しています。

失効情報は、Revocation IDによって管理されます。Master証明書は、事前にRevocation IDのレンジを確保し、Handshake証明書発行時にID割り当ててCRL Serviceに登録します。証明書の更新や事故時に明示的にCRLに登録して証明書を失効させます。このCRLのデータは、全てのサーバに配布されています。膨大なものと思われそうですが、数百メガのデータが圧縮によって数メガ程度になっているそうです。

ALTSハンドシェイク

ALTSのハンドシェイクは、双方向認証のセキュア通信に特化するためTLSのハンドシェイクを効率化し、非常に簡略化したものです。しかも、再接続にはクライアント、サーバそれぞれでチケットを用いたセッションの引き継ぎができる拡張機能も付加されています。

新規接続

ALTSハンドシェイクは、ClientInit/ServerInitとClientFinished/ServerFinishedの4種類だけです。ハンドシェイクの詳細な仕様やフォーマットは公開されていません。 f:id:jovi0608:20180116020230p:plain ClientInit/ServerInitには、各種ハンドシェイクパラメータと証明書の情報が含まれます。Forward Secrecyが使われていないので、鍵交換はClient/Server双方のHandshake証明書に記載されている公開鍵(ECDH:curve25519)を使って行います。

ALTSは双方向認証を実現するべく、サーバ・クライアントは、それぞれの証明書を受信すると、失効情報やポリシーのチェックを行います。

鍵交換で導出された共通鍵は、TLS1.3と同様にHKDF-Expand/Extract(RFC5869)を使って鍵スケジュールを行います。KDF(Key Derive Function)によって、ペイロードメッセージの暗号化するレコードプロトコルの暗号シークレット、完全性をチェックする認証シークレット、次回再接続の際に利用するResumptionシークレットの3種類を導出します。

最後のServerFinished/ClientFinishedは、ハンドシェイクが改ざんされてないことを確認するためのものです。これは認証シークレットとHMACを使って実現します。再接続用のチケットも送付します(後述)。クライアントはServerFinishedを受信したら直ちに暗号化通信を開始できるので、ALTSは1-RTTでアプリケーションデータを送付できることになります。

ALTSのフレームフォーマットは、4バイトの長さフィールド、4バイトのデータタイプのフィールドに続いてペイロードが続きます。ペイロードの最大長は現在1Mバイトで、将来もっと小さくする予定だそうです。TLSと同様にペイロードのreply攻撃に備えるため、サーバ・クライアント双方でシーケンス番号の管理も行われています。

ペイロードの暗号化の場合はAES-GCMとAES-VCM、完全性確保だけの通信ではAES-GMACとAES-VMACのいずれかが利用されます。AES-VCMはあまりなじみがありませんが、2007年頃に提案された暗号方式で、VHASHというユニバーサルハッシュを利用したAEADです。AES-VMACは、VHASHをメッセージ認証に使ったものです。

クライアントResumption

ALTSには、クラスタリング利用を前提とした再接続(Resumption)の仕組みが備わっています。TLSと同様のClient Resumptionです。 f:id:jovi0608:20180116020236p:plain 再接続用にサーバ#1からチケットをクライアントに送付します。チケットは、クライアントのidentityとResumption Secretを暗号化したものです。チケットの暗号化は、Resumption Keyを使って行われます。サーバはクラスタリングされており、同一Resumption IDを持つサーバ間で同一のResumption Keyを共有しています。

クライアントは、同一のResumption IDを持つ別のサーバ#2に再接続すると、あらかじめサーバからもらったチケットを付与してハンドシェイクを行います。サーバ#2はResumption Keyを共有しているので、チケットからResumptionシークレットを復号することが可能です。これを使ってフルハンドシェイクをせずにALTS通信を続けることができます。

サーバResumption

ALTSでは、クライアントResumptionの逆、サーバResumptionの機能も用意されています。 f:id:jovi0608:20180116020242p:plain クライアントもResumption IDでクラスタリングされており、複数クライアント間で同じResumption Keyを共有しています。今度は、最初のハンドシェイクでクライアント#1からチケットをサーバに送っておきます。同一Resumption IDのクライアント#2からサーバに新規接続があった場合、サーバはチケットをクライアント#2に送ります。クライアント#2は、Resumption Keyを共有しているのでチケットからResumption Secretを複合することができます。クライアント#2とは、新規接続だけどフルハンドシェイクなしにALTS通信を継続できることになりました。

サーバResumptionは、複数の負荷分散装置で切り替えやルーティングの変更があった場合でも、配下のサーバへの再接続が新規接続にならないといったメリットを持つことができます。。

ALTSの制限事項

ALTSには、その仕組み上いくつか制限事項があります。

KCI攻撃

ALTSは、KCI(Key Compromised Impersonation: 鍵の危殆化による成りすまし)攻撃を受ける可能性があります。これは前節で説明した通り、Resumption IDが同一の複数のホスト間でResumption Keyを共有しているため、もしどこか一つのホストの秘密鍵やResumption Keyが漏洩して危殆化すると、他のホストに成りすましが可能になってしまうということです。Resumptionの利点を得るためであり、リスクを受容するしかないです。

ハンドシェイクのプライバシー

TLSと同様にALTSのハンドシェイクは平文でやり取りされるため、どのidentityがどこに接続しにいっているのかネットワーク中間者は見ることができます。

Forward Secrecy

先述の通りALTSは、Forward Secrecyを無効にしています。証明書を頻繁に更新することでそのリスクを抑えていますが、更新期間の間はForward Secrecyを維持できません。

0-RTT

ALTSでもTLS1.3と同様に、0-RTTでアプリケーションデータの送付を実現することは可能です。しかし0-RTT で送られるデータはForward Secrecyではなく、reply攻撃に対する脆弱性も持っています。ALTSはRTTが小さい環境で使われるので、あえて0-RTTを使う必要はないと判断し、0-RTTの機能を除いています。

最後に

このようにALTSの設計や機能は、TLSに慣れていた目から見ると非常に気づきが多いものでした。

今後、ALTSの詳細な仕様やオープンソース実装が公開され、標準化の動きが出てくることを期待したいです。もっともその時にはGoogleは既に次の新しいものに移行しているでしょう。