無印吉澤

Site Reliability Engineering(SRE)、ソフトウェア開発、クラウドコンピューティングなどについて、吉澤が調べたり試したことを書いていくブログです。

Building Secure and Reliable Systems 読書メモ - Chapter 3 & 4

f:id:muziyoshiz:20200430014145p:plain:w320

SRS 本の読書メモの続きです。Chapter 5 が結構長いので、とりあえず Chapter 3〜4 の読書メモを書きました。

SRS 本はこちらから無償でダウンロードできます。

前回までの読書メモはこちら。

Part II. Designing Systems

Part II (Chapter 3〜10) では、セキュリティと信頼性に関する要求を実装するための最もコスト効率の良い方法、すなわちソフトウェア開発サイクルのできるだけ早い段階、システムの設計時にそれらに着手するということにフォーカスする。

Chapter 3. Case Study: Safe Proxies

この章は Google でのケーススタディ(Safe proxies)の簡単な紹介のみ。このケーススタディに含まれる要素は、Chapter 4 以降で詳しく紹介される。

Safe proxies とは、認可された人に対して、物理サーバや仮想マシン、特定のアプリケーションへのアクセスや状態変更を許可するためのフレームワーク。Google では、システムへの SSH 接続の必要なしに、リスクのあるコマンドのレビュー、承認、実行を行うことが出来る。

Safe proxies は本番環境への単一のエントリーポイントとなり、以下のようなことを可能にする(Figure 3-1 に Safe proxy model が図示されている)。

  • fleet 内でのすべての操作の監査
  • リソースへのアクセス制御
  • 人的ミスが本番環境へ大規模に広がることに対する保護

Zero Touch Prod という Google のプロジェクトがある。その目的は、本番環境に対する変更はすべて自動的に行われるか、ソフトウェアによって事前検証されるか、監査済みの breakglass mechanism を通して実行されるようにすることにある。Safe proxies はこれらの原則を達成するために用いられるツールセットの一つである。

Safe proxies の導入によって生じる摩擦を減らすために、この章の著者らはエンジニアと密に連携し、緊急時には brakeglass mechanism を通してエンジニアがシステムにアクセスできるようにしている。breakglass mechanism とは、緊急時にセキュリティポリシーをバイパスして操作できるようにするためのメカニズムのこと(火災報知器を鳴らすときにガラスを割る=breakglassからの連想)。breakglass mechanism は権限が強いゆえに、Multi-Party Authorization (MPA) や厳密な監査ログなどとセットで実現される。これらの詳細は Chapter 5 に書かれている。

Google Tool Proxy(Safe proxies と呼ばれるプロクシ群の1つ?)は、CLI の実行をプロクシするツールである。エンジニアはマシン上で直接コマンドを実行できない。Tool Proxy が任意のコマンドを gRPC で受け取り、ポリシーと照らし合わせ、監査ログを記録し、MPA を要求した後にコマンドを実行する。文中では borg CLI を例に挙げている。

Chapter 4. Design Tradeoffs

セキュリティ、信頼性、および機能面での要求の間のトレードオフに関する章。

セキュリティと信頼性を後回しにして一時的に開発速度を上げても、あとから重大なコストとリスクを生じる。しかし、システムのライフサイクルの初期からこれらを考慮した設計にすることで、この三者をすべて満たすことができる、というのがこの章での主張。

典型的には、機能要件(feature requirements, functional requirements)が最初に作られ、これがシステム設計に関する決定の推進力になる。それに対して、特定の機能に紐付かない、セキュリティや信頼性に関するものは非機能要件に含まれる。また、開発やデプロイのベロシティに関する要件も非機能要件に含まれる。

機能要件は仕様を書き出して、実装して、仕様通りかをテストする、という流れがわかりやすいが、セキュリティや信頼性についてはそれが難しい。信頼性とセキュリティは、システムデザインから現れてくる特性(emergent property)であり、単一の機能を実装するという類のものではない。コラム "Reliability and Security as Emergent Properties of System Design"に、この特性に関係する要素がいくつか挙げられている。

システムの初期段階から信頼性とセキュリティについて考える方法の一例として、Google で用いられている Design document template がある。このテンプレートには信頼性およびセキュリティに関するセクションがあり、p.47以降で各セクションが詳しく紹介されている。

機能要件と非機能要件のバランス、トレードオフの解決は難しい。"Example: Payment Processing" では支払い処理を例に挙げて、reliability risk を避けようとすると、security risks が出てくる、というケースを説明している。

Google ではマイクロサービスのための社内向けフレームワーク(Google Web Application Framework)を進化させてきた。

Google Web Application Framework は、アプリケーションコードがコーディングガイドラインやベストプラクティスに一致するかどうかのチェック(conformance checks)を静的または動的に適用することができる。また、開発やデプロイで必要となる共通タスクが最初から組み込まれている。フレームワークにこれらの機能が含まれているため、それを開発者が自分で作った場合に起こる脆弱性の混入を防いでくれる。

また、ビルドから SLA の計測まで自動化されていることで、error budget を消費した製品についてはリリースを止めることもできる(コラム "Reliability and Security Benefits of Software Development Frameworks" 内の記載)。

セキュリティと信頼性に対する優先度を上げることは、他の優先すべきこと(機能要件)を妨げない。むしろ上記の検査などが自動化されていれば、開発速度は上がる。セキュリティ問題に柔軟に対応できる設計ということは、新機能を追加しやすい設計ということでもある。

開発初期のベロシティ(Initial Velocity)と、長期的なベロシティ(Sustained Velocity)を区別して考える必要がある。開発初期のベロシティを重視してセキュリティと信頼性を考慮しないと、長期的にはスローダウンする。そのため、セキュリティと信頼性をチームの文化に埋め込む必要がある(チームの文化については Chapter 21)。

ここまでの感想

Chapter 3〜4 を読むと、Google はそのスケールメリットを生かして、セキュリティと信頼性に関わるツールやフレームワークを共通化しているということがよくわかります。しかし、このアプローチは Google ほどの規模がないと難しそうですし、普通の会社はどうしたらいいんだろう……というのが、ここまで読んだ率直な感想でした。

あと、個人的には Chapter 4 の文章がところどころ胸に刺さりました。例えば、コラム "Cost of Adding Reliability and Security to Existing Systems" の以下の記載。

Accommodating security and reliability requirements in an existing system often requires significant design changes, major refactorings, or even partial rewrites, and can become very expensive and time-consuming. Furthermore, such changes might have to be made under time pressure in response to a security or reliability incident— but making significant design changes to a deployed system in a hurry comes with a significant risk of introducing additional flaws.

既存システムのセキュリティと信頼性の要件を満たすためには、多くの場合、大幅な設計変更、大規模なリファクタリング、あるいは部分的な書き換えが必要となり、非常に高価で時間のかかる作業になることがあります。 さらに、このような変更は、セキュリティや信頼性のインシデントに対応するために、時間的なプレッシャーの中で行わなければならないかもしれませんが、デプロイされたシステムの大幅な設計変更を急いで行うことは、さらなる不具合を導入する大きなリスクを伴います。

あとは "Initial Velocity Versus Sustained Velocity" の節にある以下の文章も個人的には刺さりました。

Furthermore, tests retrofitted to a mature system can sometimes fall into the trap of exercising the current buggy behavior more than the correct, intended behavior.

さらに、成熟したシステムにあとから組み込まれたテストは、正しい、意図された振る舞いをテストするというより、現在のバグった振る舞いを再現していることをテストする、という罠に陥ることがあります。

そういうことってありますよね……。

いまあるシステムにとっては何の慰めにもならない文章ばかりですが、これから作るシステムについてはせめて最初からセキュリティと信頼性について考えよう、と思わせてくれる内容でした。