inthisfucking.world

💩🌎

GatekeeperとConfig Connectorを使ってGCPのリソースに対してポリシーを強制させる

Gatekeeperを使うと、Kubernetes (以下k8s) が管理しているオブジェクトにポリシーを強制することができます。Config Connector (以下KCC) を使うと、k8sを使ってGCPのリソースを管理することができます。これらを組み合わせると、k8sでGCPのリソースを管理し、Gatekeeperでそららに対してポリシーを強制できるようになります。ただ、色々な課題もあります。

この記事では、KCCでGCPのリソースを管理し、Gatekeeperでそれらに対してポリシーを強制させることに関する課題と、それらの解決策となりそうなことに関して記載します。KCCそのものはk8sのaddonで、GKE以外の環境でも使用できますが、この記事ではGCPにおいてGKEで使用することを前提としています。

ちなみにこの記事は、Mercariさんが主催していた”Open Policy Agent Rego Knowledge Sharing Meetup“に触発されて書いています 😺。

KCCで管理していないGCPのリソースに対してポリシーを強制させる

KCCで管理しているGCPのリソースは、それら作成される時 (i.e. kubectl applyによってGCPのリソースが作成される時) に、そのタイミングでポリシーを強制できます。これは、GatekeeperがKubernetes admission webhookであり、k8sのオブジェクトが作成される際にポリシーの強制の処理が実行されるためです。

新規に作成するGCPのリソースに関しては、この方法で問題ありませんが、既に存在しているGCPのリソースに関しては、admission webhookでは対応できません。既に存在しているので、新規に作成されるk8sのオブジェクトに対して実行される処理である、admission wehbookによる処理は実行されません (当然ですが)。

dry runを使用 (乱用) する

一つ考えられる解決方法は、再度admission webhookを通らせることです。kubectl applyのオプションである--dry-runserverとして実行することで、実際にk8sのオブジェクトを作成せずにadmission webhookを通すことができます。gcloud beta resource-config bulk-exportコマンドは、--resource-formatを用意しており、HCLkrmがサポートされています。既に存在しているGCPのリソースを、このコマンドを使用してkrmフォーマットで出力し、--dry-run=serverのオプションと共にkubectl applyすれば、既に存在しているGCPのリソースに対して、admission webhookを通すことができます。

この方法の良いところは、GCPのリソースが新規に作成される際に使用するGatekeeperのポリシーがそのまま使えるところです。新規にGCPのリソースを作成する際に用意するyamlファイルと、gcloud beta resource-config bulk-exportでkrmとしてエクスポートした現存するGCPのリソースに対するyamlファイルは、それらが同じものであれば中身は同じになるはずです。そのため、ひとつのGatekeeperのポリシーで、新規に作成されるGCPのリソースと、既に存在するGCPのリソースの両方に対応できます。

ちなみに、KCCがGCPのリソースを扱うために定義しているcrdはこちらにあります (ドキュメンテーションや例はこちら)。

この方法の改善できるところは、kubectl applyをdry runとして実行しているところです。dry runとしてkubectl applyを実行する場合、渡されたyamlファイルに記載のあるGCPのリソースを作るのに必要な権限が必要になります。できるだけ本当に実行した場合と同じ状況を作り出すために、権限も実際の場合と同様に確認されるようですが、これは結構危ないです。--dry-runオプションを指定し忘れると、本当に実際にGCPのリソースを作成してしまいかねません。ポリシーを強制させるために使用するサービスアカウントに対して、実際にGCPのリソースを作成できる権限を与えるのは、principle of least privilegeに反しています。

Audit Logsを使用する

もう一つ考えられる解決方法が、GCPのAudit Logsを使用する方法です。”Open Policy Agent Rego Knowledge Sharing Meetup”にて@rungさんが、GCPのAudit Logsに対してポリシーを適応している、とお話されていました。KCCで管理していないGCPのリソースにポリシーを適応させる方法として、これは非常に良い方法だと思いました。

例えば、GCEのinstances.insertが呼ばれた際に出力されるAudit Logを使用すれば、KCCで作成されたものではないGCEのインスタンスに対してもポリシーを適応させることができます。最初の方法と異なり、定期的に既に存在するGCPのリソースをエクスポートするのではなく、作成された時/更新された時などをトリガーにすることができるので、event-drivenにポリシーが適応できます。

この方法の改善できるところは、Audit Logに含まれる情報によっては、新規に作成されるGCPのリソースに使うポリシーと同じものが使えない可能性があるところです。Audit Logのエントリーは、フォーマットこそ決まっていますが、payloadは呼ばれたAPIに依存します。inputが異なる可能性があるということになるので、呼ばれるAPIごとにポリシーを用意する必要がでてくる可能性があります。若しくは、Audit LogでGCPのリソースのIDを取得し、そのIDを使って先程の方法でエクスポートすれば、この問題は解決できます。

ちなみに、GCPの公式の記事で、KCCで管理していないGCPのリソースにポリシーを適応させる方法が紹介されているので、そちらも参考になります (上記で記載したエクスポートしてポリシーを適応される方法に似たものです)。

結論

GatekeeperによってGCPのリソースにポリシーを強制させることに関して、課題と解決策を幾つか紹介しました。今回紹介した解決策は、既に存在しているGCPのリソースに対するものなので、実際にはポリシーの強制ではなく、ポリシーに準拠しているか確認する程度になっています。

KCCは比較的新しく、Gatekeeperと併用している事例、更には大規模に使用している事例も少ないと思います。より良い方法が見えてこれば、また記事を書きたいと思います。もしより良い方法、実例などあれば、コメントで共有頂けると嬉しいです。