GitOps Part 4 — Application Delivery Compliance and Secure CICD
第3回の続き、GitOpsの可観測性を説明します。
TL;DR
このブログの記事はContinuous Integration(CI:継続的インテグレーション)を既に導入したKubernetesユーザーやContinuous Deployment (CD:継続的デプロイ)を採用したいと思っているKubernetesユーザーに向けて書かれています。主にセキュリティとコンプライアンスに書きたいと思います。今回は継続的なデリバリーパイプラインの安全性がどのくらい上がるのかを実際にお見せします。また。GitOpsを使ってベストプラクティスがシステムチェンジの監査証跡を完成させることができるということをデモンストレーションします。
Getting startedはじめに
「KubernetesのためのGitOps と高速 CICD 」という記事を読まれていない方は先にこちらから読まれることをおすすめします。この記事では、GitOpsを実行するための3つの方法をおすすめしています。
- Weave Cloudは GitOps スタイルの中のGCP上のCICD と Observability(可観測性) への近道である。
- Kelsey Hightower氏のKubeconでの実践的なDIY approachについて動画(video)
- Weave Flux は私たちのオープンソースCDであり、自動化ツールをリリースする。そして、Weave Cloudの中で使用される。
この投稿の中で、私はセキュリティとコンプライアンスの重要なポイントをご紹介するためにWeave Fluxについて主にお話したいと思います。FluxはKubernetesのためのWeave Cloudデプロイサービスのコアの部分です。Fluxのおかがで下のようなベストプラクティスを実現することができるのです。その方が、すべて自力でやったりもっと古いCDツールをKubernetesへ導入するよりはもっと簡単にできるからです。ただこれは強制ではないので、ご自身のお好きなようにしてください。
Three best practices
以下があなたがすべき3つのことです。
- システムとの重要なやり取りを記録しておく。例えば、誰がいつ、なぜ変更したのか。
- もしその代わりにコンフィグレーションをアプデートできたとしたら、不必要にスクラッチからイメージを再構築しない。それぞれのコンテナイメージを1回だけ構築してそれぞれのテストシーケンス(テスト手順)/環境を通して、それを「プロモート」する。実行するたびに、再構築はしないようにする。でもGitの中でまだdeclarativeコンフィグレーションをアップデートする必要がある。
- プルベースのデプロイを使う。Kubernetesクラスターの中にアップデートをプッシュさせないようにするか、もしくは、手動でKubectleを使うか。
それでは今から上の3つについて詳しく見ていきます。まず最初に3の「プッシュvsプル」から説明します。
この以前の記事では動画 andスライドが見れますが、どのようにWeave FluxがKubernetesのオペレーションパターンを実行しているかをお話しています。この通常の定義では、オペレーター Kubernetesによって管理されてるアクター(実際の動作主)で、クラスターのコンフィグレーション、セキュリティ、アベイラビリティ(可用性)を受け継ぐことができます。
こうすることで「すぐ使える」よりよりセキュリティを適用することができます。それはなぜでしょうか?Fluxは自分のKubernetesクラスターの中に住むエージェントです。アクセスすることを許可されたイメージレポジトリーと全てのコードへのアップデートをリッスンします。そしてイメージとコンフィグレーションアップデートをクラスターの中にプルします。
Fluxは以下のことができるので、プルアプローチはより安全です。
・Kubernetesのロールベースのアクセスコントロール(RBAC)、ポリシー、セキュリティに許可されたオペレーションのみ実行する。トラストはクラスターと共有され、別々に管理されることはない。
・すべてのKubernetesオブジェクトに対してネイティブのようにバインドしている。そしてオペレーションが完了したかどうか、リトライする必要があるかどうかを知っている。
これは最近の典型的な「プッシュ」アプローチと対照的なものです。
・アクタープロセスはクラスターの外に存在し、イメージをロードする実行コマンドによってデプロイorchestrationを責任を持って実施する。
・直接のアップデートを実行するためにコマンドラインをタイプすること、もしくはCIジョブとして走るスクリプトの中でアップデートをエンコードすること。
もしきちんと対処して実行すればこのモデルは安全になります。というのもそれはクラスターの中とGitの中でプロダクションと共にインタラクションを制限するためにまだRBACを使うからです。しかし、それをぐちゃぐちゃにするのはもっと簡単です。あなたは、自分のクラスターのトラストドメインの外で動いていて、それを統合しています。そのためすべてのトラストドメインと外部の証明認証を手動でセットアップしなければなりません。そして自分自身の強化をする必要があります。これらを実行するときには注意をしてください。またリライトなしに変化するのは全く適していません。だからCIシステムはプロダクションのためにベクターを攻撃するのです。まとめると、もしちょっとでも注意を怠ると、CIは自分のシステムにとっての侵入口になるということです。
How secure is your pipeline?
もしこういう分野にご興味をお持ちでしたら「あなたのCICDパイプラインはどのくらい安全か」という記事を読むことを強くおすすめします。私たちのプロジェクト・マネージャーであるStuart Williamsが書いたものですが、許可にアクセスするCIシステムへの「デザインによるセキュリティ」について書かれています。
The role of CI in GitOps
GitOpsの中では、CIシステムはクラスターへ直接アクセスすることは全くありません。あなたはまだビルドを走らせるために、またリグレッションテスト(回帰テスト)のためなどに、CIを使っていますね。そのためCIはアップデートを書いて、関連したレポジトリーの中にイメージを書いたりします。これは本当に素晴らしく機能するのです!でも直接アップデートをプッシュするためにCIを使うのはやめてください。そして可能であればkubectlは避けてください。
Speed of updates and recovery from failure
もしCIパイプラインがスクリプトを使ってクラスターの中に変化をプッシュしたら、それには時間がかかるし、時には壊れてしまうことがあるということに気づくかもしれません。アップデートが壊れる主な原因はそのスクリプトが脆いからです。そしてもし失敗があれば自分の状態は分からないかもしれません。
私たちがおすすめするアップデートを使うのが早くて強いです。Fluxはクラスターにローカルでもネイティブでもアクセスします。そして、Fluxはそれが確認されたとき(そしてどのように確認されたか)にのみ制御されます。マルチFluxエージェントを簡単に走らせることができるのです。Fluxのエージェントライフサイクル、失敗、リカバリー、アベイラビリティ、スケーラビリティは全てKubernetesによって管理されています。そしてFluxはクラスター変化の記録としてGitを使います。そのためもしデプロイの最中に何か不具合が起きたらいつもリカバリー可能ですし、必要であればロールバックしたりする必要があります。
補足:もちろん、ビルドイメージをコンテナイメージレポジトリーにプッシュすると遅くなることがあります。でもだいたいその失敗のケースは理解しやすいです。
Testing in production
ここに、Cindy Sridharan氏(@copyconstruct on Twitter)が作成したもっといいイメージがあります。
このイメージは Observability bookについてのCindyの tweets から引用しています。私たちのブログとの関連性は私たちがもっともっと「プロダクションのテスト」を見ているというところです。デプロイとリリースは早くしないといけませんし、安全である必要もあります。デプロイに対してプル・ベースのアプローチを使うともっと簡単になります。例えばKubernetesのためのFluxです。高速CICDは素晴らしいのです。というのも早くテストができるし、顧客の満足と利益のために、いわゆるcontinuous experimentation(持続的な研究)ができるからです。
Don’t rebuild images if you can change config instead
GitOpsの中では、理想的に私たちはシステムの私たちが望む状態の完全な記述があります。Git は自分たちが望む状態のための信頼できる情報源 です。 以前のパイプラインについての記事の中でも書いてあるようにGitOpsの中では私たちは以下のようなベストプラクティスをビルドしています。
・DevOps と Gitバックされたパイプライン
・コードとしてのインフラストラクチャー(別名 config-as-code)
・変化しないデプロイアーティファクト
また私たちはそれらのプラクティスをKubernetesとその他のクラウドネイティブテクノロジーに統合しています。そして、私たちの望みは完全なるdeclarativeアプリケーションデリバリーモデルです。
DevOpsとKubernetesとクラウドネイティブプラクティスを統合することは以下の結果を生みました。
・全てのコンフィグレーションはdeclarativeで全てのことが記述され、観察される
・イメージが変わっても、コンフィグレーションは変化することがある。
・ビルドからコンフィグレーションを別々することができるし、個別にアップデート可能
・「コードとしてのコンフィグレーション」から「コンフィグレーションとしてのops」へ移る。
だからベストプラクティスにとってこれらはどういう意味なのか?
変わらないインフラストラクチャーはベストプラクティスです。でも「何を」インフラストラクチャーとするかは日々進化しています。コンテナリゼーションと共に、私たちはコードと他のソース情報を不変のコンテナイメージの中でビルドします。declarativeなコンフィグレーションと共に、私たちは値のセットとしてシステムをパラメータ化して、それをすべてGitの中で保存します。それらの値は、ランタイム時に変わります。ランタイムは、システムを部分的に変えます。
Kubernetes YAMLファイルはdeclarativeなコンフィグレーション
の例です。もしきちんと承認されたり、認証されたら、Kubernetes YAMLファイルをアップデートすることが可能です。GitOpsはそのアップデートを促します。というのも重要なシステムチェンジをするために、コードからイメージをリビルド(再ビルド)する必要もないし、したくもないからです。しかし、全てのシステムチェンジをGit(あなたの望む状態のための信頼できる情報源)の中に表出したいとも思っているはずです。
Weave Fluxはイメージレポジトリーと同じようにコンフィグレーションレポジトリーを観察することで、このような場合に対処します。もしそのコンフィグレーションがアップデートされたら、そしてそのイメージが変わらずに残っていたら、FluxはアプリケーションをアップデートするためにKubernetesクラスター内部でデプロイをorchestrateするでしょう。プル・ベースのデプロイと同じように、これにはいくつかの機能的な利点があります。
- より早く、そしてより強靭に:いつも正しい方法でアプライのチェンジをリビルドする必要はない。リビルドは、デリバリーサイクルにレイテンシーを追加する。そして毎回成功するとは限らない。
- アタックサーフェスを減らす:こうすることで、「誰がいつそれをチェンジするのか」という実用的なアクセスコントロールモデルを使うことになる。コードチェンジの必要なしに、Gitの中に正しく記録される、強いアプリケーションアップデートのカテゴリーを持つとすごく役に立つ。
- GitOpsパラダイムの中に残っている間、ラッチング and カナリアのような転換パターンをサポートする。例えば、アドミニストレーターは最新のよい状態のスナップショットを取っている間、ますます増加するロールアウトをすることができる。
でも以下が一番の部分です。
・そのアプローチは付加的である。現存するCIを取り除かないように。それがイメージレポジトリーに書き込まれていて、Fluxを追加するように確認すること。最初に、すべてのこのデプロイがDev,Test,UATそしてプロダクションクラスターになるマルチ・クラスター パイプラインに合わせてすべてこれが調整する。
・「GitOpsの中のマルチ・クラスター パイプライン はここで提供される」ということについての説明
最後に三番目のベストプラクティスについて話をしましょう。ベストプラクティスの中ではGitがチェンジを記録するのを助けてくれます。
Record everything in Git to have audit and compliance
Weaveworksの顧客はSOC 2 コンプライアンス に合格するために最近はGitOpsプラクティスを使っています。ここで大事なのは、そのテストを通過するために高価なコンプライアンス製品を購入するように言われるのが普通だということです。少なくとも日常的なケースのためではないことのために、そのような高価な製品を飼う必要はないと私たちは思っています。
もし、正しいことをするならば、監査人はGitを見て、誰が、いつ、なぜ、そしてどのように走っているシステムデプロイへの影響を変化させたのかということが分かると思います。覚えておいてほしいのは、同じアプローチがHIPAAAやPCIでも役に立つということです。そしてその全てのテストが有名なプロセス・オーバーヘッドを紹介します。GitOpsの中では、それは通常のデベロッパーのプラクティスの中に含まれます。それでは、その理由を見てみましょう。
そのコアコンセプトは、会社に何ができるか、従順(オビィディエンス)記録をし続けることについて、役割とルールの間で分かれる必要があるということです。例えば、誰がプロダクションのコードを変えられるか、ということと、誰がプロダクションのコードのモニタリングを変えられるかという二つの差は明確です。理論上は、これは、その会社が2人の悪者がプロダクションの中へ邪悪なコードをこっそりと言ってしまうということを意味します。これを小さくてすばしっこいチームがいて早く動くデリバリー環境のなかで管理することは、難しいです。昔からある大企業がvelocityを潰そうとする理由はここにあります。
Threat Stackのブログからの引用をしたいと思います。「誰が最後に承認されていないシステムファイルにチェンジをしたのか?」 私たちが適役を探すことができるし、私たちがGitの中でそういう変化を追うことができます。ただ少なくとも以下の2つのroleが必要です。
- Roleがソースへアクセスを書いた
- Roleはプロダクションを見るが、変化の余地なし(全くないこともない)
GitHub RBACを使うことで誰がそのチームにいるかをコントロールでき、それによってアクセスされたかどうかもコントロールできます。そして役割を提供してくれます。GitHubは変化が起きるたびに、すべての変化を追い続けます。
ソースチェンジをキャプチャーするだけでは十分ではありません。リリース、ステージング、ローリングをトラックしなければいけません。そして、クラスターオブジェクトを生かすためにどのようにイメージやコンフィグレーションがチェンジするのか理解する必要があるのです。Weave Fluxがあなたに代わって記録をしてくれ、すべてGitに書き込んでくれます。これはあなたの望んでいる状態が最新で正しくobservable(観察可能)であるということを意味します。そしてすべて自分が記録する必要があるものは、監査役が来る日までずっと記録され続けます。
GDPR and security by design
GDPRを使っている方に簡単にお話をしておきますが、GDPRを使っていない人はあまり関係のない話なので飛ばしてください。「デザインによるセキュリティ」はGDPRにとっての必要条件です。私たちのアプローチであるGitOpsはOWASPと提携しています。OWASPはこれのためのプラクティスを定義づける大きなプロジェクトです。特に私たちは、自分たちのベストプラクティスがそれらのOWASPの情報セキュリティ規則とすごく深い関係があると思っています。
- Confidentiality(機密性) — 許可されたユーザーのためのデータにアクセスすることのみを許す
- Integrity — データが許可されていないユーザーによって変更させられることを認める
- Availability — システムとデータが必要なときに許可されたユーザーが使用することを認める
この3つのベストプラクティスは高価なものを買わなくても、セキュリティとコンプライアンスにすごく役に立つということを覚えておいてください。
- Gitで記録し続ける
- コンフィグレーションを使っているのであれば、不必要なリビルド(再ビルド)は避ける
- プル・ベースのデプロイを使う
Orangesys.ioでは、kuberneteの運用、DevOps、監視の手伝いをさせていただいています。ぜひ私たちにおまかせください。