本文の内容は、2022年7月26日にEduardo Mínguezが投稿したブログ(https://sysdig.com/blog/gitops-iac-security-source/)を元に日本語に翻訳・再構成した内容となっております。
GitOpsデプロイメントモデルにセキュリティの問題がある場合(たとえば、タイプミスによる権限の設定ミス)、これは、ランタイムで検出されるまで伝播されてしまうかもしれません。ほとんどの場合においてランタイムでセキュリティイベントがスキャンまたは検出されてしまうのです。
インフラストラクチャーに潜在するセキュリティ問題を発生源で修正できるとしたらどうでしょうか。
基本的なことから始めていきましょう。
Gitとは?
Gitは、オープンソースの分散型バージョン管理システムです。ファイル(通常はソースコードのようなテキスト・ファイル)に加えられた変更を追跡し、共同作業モデルを可能にし、促進します。現在では、バージョン管理システムのデファクト・スタンダードとなっています。自分のノートパソコンに自分のgitリポジトリを持つことも、自分のサーバーにホストすることも、GitLabやGitHubのようなプロバイダーを利用することも可能です。
リポジトリを管理する方法にはさまざまな「フロー」(git-flow、github-flowなど)がありますが、gitの使い方の基本例は次のようなものです。ファイルの変更は、ユーザーがリポジトリを「フォーク」し、「ブランチ」で適切な変更を行うことで「コミット」されます。
次に、ユーザーはそれらの変更をリポジトリに含めるためのリクエスト(「プルリクエスト」、「マージリクエスト」、または単に「パッチを送る」のいずれか)を作成します。
その後、通常「オーナー」とリクエストを作成したユーザーとの間で議論が行われ、すべてがうまくいけば変更が受け入れられ、リポジトリに追加されます。
注:git pull request の仕組みについてもっと詳しく知りたい方は、こちらをご覧ください。
実際の例を見るには、お気に入りのオープンソースの GitLab や GitHub リポジトリをブラウズして Pull Request (あるいは Merge Request) タブを表示します (面白い例としてはこちらも参照ください)。提案された変更点、コメント、ラベル、誰が変更を提案したか、提案された変更点に対して検証を行うツール、リポジトリを見ている人に送られる通知などを見ることができます。
GitOpsとは?
簡単に言うと、GitOps はソフトウェア資産の単一の真実の源として git リポジトリを使用し、ソフトウェアに git デプロイメントモデル(プルリクエスト、ロールバック、承認など)を活用できるようにする方法論にすぎません。書籍(The Path to GitOps、GitOps and Kubernetes、GitOps Cloud-native Continuous Deployment)やホワイトペーパー、数え切れないほどのブログ記事がありますが、ここ数年の進化を簡単に見て、GitOpsという目的について詳しく説明しましょう。
クラウド以前は、アプリケーションをホストする新しいサーバーを追加するのに何週間もかかりました。許可を得て、購入し、多くの手動タスクを実行しなければなりませんでした。その後、仮想化によって、事態はより簡単になりました。あるスペックの仮想マシンを要求すると、数分後にはアクセスできるようになります。
そして、クラウド、サーバー、ネットワーク、ストレージ、データベース、メッセージングキュー、コンテナ、機械学習、サーバーレス…といったものをAPIコールでリクエストすることができるようになりました。リクエストして、数秒後にはそれが手に入る、そんな感じです。使った分だけお金を払えばいいのです。これは、インフラストラクチャーがAPIコールを実行するコードとして管理できることも意味します…そして、あなたのコードはどこに保存されるのでしょうか?git リポジトリ(または他のコンテンツバージョンシステム)です。
GitOpsという用語は2017年にウィーブワークスによって作られたもので、OpenGitOpsを言い換えると、GitOpsシステムは以下の原則に基づいています。
- 宣言型:”what “を定義するものである。
- バージョン管理され、不変である:”git “の由来。
- 自動的にプルされる:エージェントが望ましい状態とコードで起きている変化を観察する。
- 継続的に調整される: Kubernetesについて誰か言及しましたか?
注:GitOpsには、例えばプッシュとプルの違いや、構成管理の扱い方など、若干異なるアプローチが存在します。これらは高度なトピックですが、今は基本に忠実でありましょう。
次の図は、GitOps システムを簡略化したものです。
開発者が変更を送信し、GitOpsのプロセスとKubernetesにデプロイされたエージェントが変更を監視しているGitOpsのダイアグラム
- コードの変更は、ユーザーによってGitリポジトリに送信されます。
- そして、その変更をアプリケーション自体に取り込むために、リポジトリ上でプロセスが起動され、その新しいコードに対して自動化ツールを実行して検証することも含まれます。
- すべてが整うと、リポジトリを監視しているKubernetesクラスターで稼働するGitOpsエージェントが、望ましい状態(リポジトリ内のコード)と現在の状態(Kubernetesクラスター自体で稼働するオブジェクト)との間の調整を実行します。
Gitをベースにしているということは、開発者にとっては摩擦がないことを意味します。新しいツールに悩まされることなく、Gitリポジトリでコードを管理するのと同じプラクティスを適用することができるのです。
GitOpsツールについては、CNCFのインキュベート・プロジェクトであるFluxやArgoCDのようなオープンソースのツールを含め、すでにいくつかのツールが利用可能になっています。
GitOpsによるアプリケーションの定義がどのようなものかを知るために、簡単なアプリケーション(GitHubのリポジトリに格納されている)をFluxやArgoCDで管理する例を挙げてみます。
Fluxの場合:
--- apiVersion: source.toolkit.fluxcd.io/v1beta2 kind: GitRepository metadata: name: my-example-app namespace: hello-world spec: interval: 30s ref: branch: master url: https://github.com/xxx/my-example-apps.git --- apiVersion: kustomize.toolkit.fluxcd.io/v1beta2 kind: Kustomization metadata: name: my-example-app namespace: hello-world spec: interval: 5m0s path: ./myapp prune: true sourceRef: kind: GitRepository name: my-example-app targetNamespace: hello-world
ArgoCD を使う場合:
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: my-example-app namespace: hello-world spec: destination: namespace: my-example-app server: https://kubernetes.default.svc project: default source: path: myapp/ repoURL: https://github.com/xxx/my-example-apps.git targetRevision: HEAD syncPolicy: automated: {} syncOptions: - CreateNamespace=true
どちらもアプリケーションマニフェストを格納する Git リポジトリ (デプロイメント)、ネームスペース、その他いくつかの詳細を参照しています。
GitOpsとIaCの比較
Infrastructure as Code は、インフラストラクチャーのビルドブロックを、さまざまなテクニックやツールを使ってコードとして扱う方法論です。つまり、VM、コンテナ、ネットワーク、ストレージなどのインフラストラクチャーを、お気に入りのインフラストラクチャープロバイダーのウェブインターフェースを使って手動で作成する代わりに、それらをコードとして定義し、terraform、 crossplane、 pulumi など、選んだツールで作成/更新/管理します。そのメリットは非常に大きいのです。インフラストラクチャーをコードであるかのように管理でき(今はコードです)、開発のベストプラクティス(自動化、テスト、トレーサビリティ、バージョン管理など)をインフラストラクチャー資産に活用することができます。実際、インフラストラクチャーは単なるコード以上のものであるため、代わりに「Infrastructure as Software」という言葉を使おうという動きがあります。
このトピックに関する情報はたくさんありますが、次のリソースが良い出発点となるでしょう。
おそらくお分かりのように、GitOpsはインフラストラクチャーを定義するための宣言型モデルとしてInfrastructure as Codeを活用しています。実際、IaCはGitOpsの基礎の1つです。しかし、IaCはGitOpsの他の原則を義務づけているわけではないので、それ以上のものなのです。
GitOpsとDevOpsの比較
「DevOps」という言葉には、さまざまな定義があります。誰に尋ねるかにもよりますが、簡単に言うと、「DevOpsとは、摩擦を減らし、高速にソフトウェアをビルドして提供するためのプラクティスとツールの組み合わせである」です。GitOpsはDevOpsのプラクティスにマッチしたフレームワークを提供するため、DevOpsの方法論はGitOpsを活用できますが、厳密には必要ではありません。
NoOpsはどうでしょうか?
NoOpsは2021年にForresterによって作られた造語で、IT環境を抽象化し、手動で管理する必要がないほど自動化する運用を実現するためのラディカルなアプローチです。GitOpsは、Gitリポジトリにある望ましい状態のものに修正することで、手動による変更を減らすのに役立ちますが、IT環境全体に本当の意味でのNoOpsを適用することは、今日時点では現実の目標ではなく、憧れ的なゴールと言えます。
GitOpsはKubernetesだけのものなのでしょうか?
いいえ。Kubernetes、コントローラーパターン、Kubernetesオブジェクトを定義する宣言型モデルは、GitOpsの方法論に完全にマッチしていますが、KubernetesなしではGitOpsの方法論が適用できないというわけではありません。Kubernetes以外でGitOpsを使う場合、冪等性の処理、アセットの削除/作成、Secret管理など、いくつかの課題があります。しかし、GitOpsの原則はKubernetesなしでも(そして少し創造性を働かせれば)適用可能です。GitOpsとセキュリティ
ここで、セキュリティの側面についてお話ししましょう。ほとんどのセキュリティツールは、潜在的な脆弱性や問題をランタイムで検出します(遅すぎるくらいです)。それらを修正するためには、リアクティブな手動プロセスを実行する必要がありますが(例えば、k8sオブジェクトのパラメーターをkubectl editで直接修正する)、理想的には、修正がソースで行われ、サプライチェーン全体に伝搬されるようにすることです。これが「Shift Security Left」と呼ばれるものです。手遅れになる前に問題を修正することから、問題が発生する前に修正することへ。これは、すべてのセキュリティ問題をソースで修正できるということではありませんが、ソースに直接セキュリティレイヤーを追加することで、いくつかの問題を防ぐことができます。
まず、一般的なセキュリティの推奨事項が適用されます。
- 攻撃対象領域を減らす
- Secretを暗号化する(External SecretsまたはSealed Secretsを使用)。
- ネットワークのセグメンテーション
- RBAC
- ソフトウェアを常に最新に保つ
- 最小権限の適用
- 監視と測定
- …
GitOps の方法論が一般的なセキュリティを向上させるシナリオをいくつか見てみましょう。
- 手動での変更を避ける/拒否する(ドリフトの回避)。Git リポジトリは真実の源です。アプリケーションの定義を変更しようとすると、GitOpsツールはGitリポジトリに保存されているバージョンを適用することでそれらの変更を元に戻します。クラスター上で実行されているオブジェクトとGitリポジトリに保存されている定義の違いを表示するGitOps UI
- 変更のロールバック。アプリケーションのデプロイメントで何らかのパラメーターを変更することによって、特定のコミットで潜在的なセキュリティ問題を発生させたと想像してください。Git の機能を活用することで、必要に応じてソースで直接変更をロールバックすることができ、GitOps ツールはユーザーの操作なしにアプリケーションを再デプロイします。元に戻された変更を表示する GitOps UI
- 迅速な対応。アプリケーションで脆弱性のあるコンテナ・イメージ (例: MariaDB) を使用していることが判明した場合、PR を作成してデプロイ・ファイルにタグを更新するだけで、GitOps ツールは新しいタグを新しいデプロイで使用するようになります。GitOpsツールによって実行されたデプロイの詳細がGitOps UIに表示されます。
- トレーサビリティ。Gitの機能を使えば、ファイルがいつ変更されたか、変更そのもの、変更をプロモートしたユーザーを簡単に確認することができます。監査ログを無料で手に入れることができます。コミットされた変更のログを表示するGitHubのUI
- ディザスターリカバリー。ここでも、Git リポジトリが真実の源となります。何かがあってアプリケーションを再デプロイする必要がある場合、その定義がそこにあります(もちろん、データ自体など他のものに対するディザスターリカバリープランが必要です)。
- アクセスコントロール。Git リポジトリに対してユーザーごとに異なるパーミッションを適用したり、「2 回の肯定的なレビューの後にのみ変更をマージする」などのポリシーを適用したりすることができます。
これらの利点は、GitOps の手法を使用してセキュリティ体制を改善することを正当化するのに十分なものであり、すぐに使えるものです。私たちは、もっと多くのことを行うことができます。GitHubやGitLab、その他のGitリポジトリプロバイダーでは、プルリクエストによるものも含めて、Gitリポジトリで行った変更に基づいてアクションやパイプラインを実行できるので、可能性は無限大です。いくつか例を挙げます。
- Linting。アプリケーションの定義はコードです。定義に間違った構文がないか、パラメータがないか、などをチェックするとしたらどうでしょうか。実行した変更に対して実行できるツール(megalinterなど)があるので、後で驚かないようにすることができます。実行されたテスト、アラート、詳細を表示するmegalinterの出力
- テスト。一時的なKubernetesクラスターを自動生成して、変更を加えたアプリケーションを実行し、それに対していくつかのテストを実行することも可能です。KubernetesクラスターをデプロイするGitHubのActionsログを表示するGitHub UI
- 脆弱性スキャン。使用しているコンテナイメージを環境にデプロイする前に脆弱性をチェックすることで、脆弱性の有無を確認します。プルリクエストで直接コードをチェックするポリシーの詳細表示を示すGitHub UI
- Policy-as-code。OPAを活用することで、マニフェストにポリシーを適用し、潜在的な問題やカスタムポリシーをチェックすることもできます。GitHub UI に、実行された変更に対して OPA ポリシーを実行する GitHub Actionsの出力が表示されている。
最終的な考察
GitOpsの方法論は、他のツールを追加することなく、デプロイメントモデルとセキュリティの利点にいくつかの改良をもたらします。ソースコードに直接「シフトレフト」レイヤーを追加することでセキュリティポスチャーを改善し、プルリクエストモデルの柔軟性のおかげで、ランタイムに影響を与えたり、変更したりせずに、簡単に追加のセキュリティチェックを追加することができます。