Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Kubernetesとクラウドのシークレット管理:第2回

By Alexei LedenevMay 7, 20205 min read

このページはEnglishDeutschEspañolFrançaisItalianoPortuguêsでもご覧いただけます。

1 2vmdytkvuqf4gosqpgyjka

APIキー、パスワード、証明書などの機密データをクラウドネイティブなシークレット管理サービスに保管し、K8sクラスターから安全にアクセスする方法を解説します。

はじめに

シークレットは、多くの本番システムを動かすうえで欠かせない要素です。意図せぬ漏えいは最大級のリスクであり、確実に対策しなければなりません。開発者はアプリケーションのシークレットを守るために最善を尽くす必要があります。

マイクロサービスアーキテクチャに移行し、複数のサービスがそれぞれ異なるシークレットを必要とするようになると、この課題はさらに複雑になります。意図せぬ漏えいを防ぎながら、アプリケーションのシークレットをいかに配布・管理・監視・ローテーションするか——新たな課題が立ち上がります。

前回の記事(第1回)では、AWSとGoogle Cloudのシークレット管理サービス(AWS Secrets ManagerAWS SSM Parameter StoreGoogle Cloud Secret Manager)を、対象Podに手動で追加した doitintl/secrets-initinitContainer を介してKubernetesと連携させる方法を紹介しました。

今回は、これらのクラウドシークレット管理サービスを連携させるKubernetesネイティブなアプローチを紹介します。

クラウドシークレットの自動注入

Kubernetes Deployment YAMLファイルを手作業で書き換えて secret-init をコンテナの init システムとして使うことも可能ですが、できれば自動で、しかもクラウドシークレットを参照しているPodに対してのみ適用されるのが理想です。幸い、Kubernetesには mutating admission webhook という仕組みがあり、コンテナ作成前に任意のPodを検査・変更できます。

doitintl/kube-secrets-init は、DoiT International が公開しているオープンソースプロジェクトで、AWSとGoogle Cloud双方のマネージドシークレットに対応した、クラウドシークレット注入用のKubernetes mutating admission webhook を実装しています。

kube-secrets-init はKubernetesクラスターを監視し、新規作成または更新されたPodのうち、クラウドシークレットを直接(環境変数経由)または間接的に(Kubernetesの SecretConfigMap 経由)参照しているものに対して、doitintl/secrets-init ユーティリティを組み込んだ initContainer を追加します。

0 hvfcvwhqc bmz8jd

AWS Secrets Managerとの連携

環境変数の値として、AWSシークレットの ARN 参照を指定できます。secrets-init は、指定されたARNをもとに環境変数の値を、参照先のシークレット値へと解決します。

https://gist.github.com/930c9ea733557f9715f976df042bf361

AWS Systems Manager Parameter Storeとの連携

AWS Systems Manager Parameter Storeを使って、アプリケーションのパラメータやシークレットを保管することもできます。

環境変数としてAWS Parameter StoreのARN参照を指定すると、secrets-init はそのARNをもとに環境変数の値を、参照先のParameter Storeの値へと解決します。

https://gist.github.com/f7d9a81d5e239cdd734989a689d46f82

Google Secret Managerとの連携

環境変数の値として、Google Secret名(先頭に gcp:secretmanager: を付与)を指定できます。secrets-init は、指定された名前をもとに環境変数の値を、参照先のシークレット値へと解決します。シークレット名にバージョンを含めれば、特定バージョンのシークレットを参照することも可能です。

https://gist.github.com/d121cce3a9d4664a876deb95f18493d7

前提条件

AWS

AWS Secrets ManagerやParameter StoreからAWSシークレットを解決するには、secrets-init アプリケーションを、以下のいずれかのIAMポリシーを付与したAWS IAMロールで実行する必要があります。

AWS Secrets Managerの場合:

https://gist.github.com/7348301b4882a564cbd9644d6697c3eb

AWS Systems Manager Parameter Storeの場合:

https://gist.github.com/3f3dd3d015a4c000341491c18ac2c4b7

EKSクラスターで実行する場合は、AWS IAM Roles for Service Account の利用を推奨します。コンテナを実行しているEC2インスタンスにIAMロールを割り当てる方法もありますが、こちらはセキュリティ面で劣るとされています。

Google Cloud

Google Secret ManagerからGoogleシークレットを解決するには、secrets-init アプリケーションを、対象シークレットへのアクセス権限を備えたIAMロールで実行する必要があります。たとえば、Google Service Accountに、定義済みのGoogle IAMロール Secret Manager ViewerSecret Manager Secret Accessor の2つを割り当てる方法があります。

GKEクラスターでは、Workload Identity を用いてKubernetes PodにIAMロールを割り当てられます。コンテナを実行しているGCEインスタンスにIAMロールを割り当てる方法もありますが、こちらはセキュリティ面で劣るとされています。

deployment.yaml ファイルの --provider=google フラグのコメントアウトを解除してください。

Webhookのデプロイ

  1. kube-secrets-init webhookサーバーをデプロイするには、Kubernetesクラスター内にwebhook用のサービスとデプロイメントを作成します。手順自体はシンプルですが、サーバーのTLS設定だけは注意が必要です。deployment.yaml を見ると、証明書と対応する秘密鍵のファイルがコマンドライン引数から読み込まれ、そのパスはKubernetesシークレットを指すボリュームマウントから渡される構成になっています。

https://gist.github.com/b861984a2be2f2f63596f089f417cefc

重要なのは、対応するCA証明書を後ほどwebhook構成に設定し、apiserver がその証明書を受け入れるよう認識させることです。ここでは、Istioチームが当初作成した証明書署名要求生成用のスクリプトを再利用します。続いてそのリクエストをKubernetes APIに送信し、証明書を取得して、その結果から必要なシークレットを作成します。

まず webhook-create-signed-cert.sh スクリプトを実行し、証明書と鍵を保持するシークレットが作成されたか確認します。

https://gist.github.com/43135c6af29328bcd74a37b0df5188f8

シークレットを作成できたら、続いてデプロイメントとサービスを作成します。これらはKubernetesの標準的なデプロイメントおよびサービスのリソースです。ここまでで構築したのは、ポート 443 のサービス経由でリクエストを受け付けるHTTPサーバーにすぎません。

https://gist.github.com/3971cf1f46f5a57d11d922ed84b0543f

Mutating Admission Webhookの設定

webhookサーバーが稼働したので、apiserver からのリクエストを受け付けられる状態になりました。ただし、その前にKubernetes側で構成リソースをいくつか作成しておく必要があります。まずvalidating webhookから設定し、mutating webhookは後で構成しましょう。webhook構成 を見ると、CA_BUNDLE のプレースホルダーが含まれているのが分かります。

https://gist.github.com/fcafa7ed3b3c3b951b7fad3c0d5fbdb6

構成内のCA_BUNDLEプレースホルダーを実際のCAに置き換える 小さなスクリプト が用意されています。validating webhook構成を作成する前に、次のコマンドを実行してください。

https://gist.github.com/6d5bb7724cef04e9e6a2af12da917a21

続いてmutating webhook構成を作成します。

https://gist.github.com/f946d6046cc1a76a21526c346ca403c1

secrets-init-webhookのRBAC設定

secrets-init-webhook で使用するKubernetes Service Accountを作成します。

https://gist.github.com/0cda887b586609cbdbb700f7412e70ad

webhookのサービスアカウントに付与するRBAC権限を定義します。

https://gist.github.com/1205f1a5d2f449cc3340a404ea474b77

まとめ

本記事がお役に立てば幸いです。ご意見・ご質問をお待ちしています。

doitintl/kube-secrets-init のGitHubプロジェクトへの貢献(Issue、機能提案、PR)も歓迎します。

Alexeiの記事をもっと読みたい方は、ブログをご覧いただくか、Twitterで Alexeiをフォロー してください。