Cloud Intelligence™
Kubernetesとクラウドのシークレット管理:第2回
このページはEnglish、Deutsch、Español、Français、Italiano、Portuguêsでもご覧いただけます。
About Alexei Ledenev
Long ago, in a perfectly ordinary corner of the software universe, I started persuading computers, clouds, containers, and Kubernetes clusters to behave in ways that were useful, reliable, and occasionally intentional.
Since then, I’ve led architecture and engineering teams, built cloud platforms, designed distributed systems, and created open-source tools such as pumba, KubeIP, kube-secrets-init, and ccgram - because apparently production systems were not failing in enough interesting ways on their own.
My work lives somewhere between Software Architecture, Kubernetes, Cloud, chaos engineering, and AI infrastructure: the sort of place where dashboards glow green, alarms remain suspiciously quiet, and everyone hopes DNS has read the plan.
I enjoy building practical tools for complicated systems, automating the boring parts, understanding the dangerous parts, and reminding infrastructure - gently, but firmly - that uptime is not just a lifestyle choice. 🪐
My personal page
APIキー、パスワード、証明書などの機密データをクラウドネイティブなシークレット管理サービスに保管し、K8sクラスターから安全にアクセスする方法を解説します。
はじめに
シークレットは、多くの本番システムを動かすうえで欠かせない要素です。意図せぬ漏えいは最大級のリスクであり、確実に対策しなければなりません。開発者はアプリケーションのシークレットを守るために最善を尽くす必要があります。
マイクロサービスアーキテクチャに移行し、複数のサービスがそれぞれ異なるシークレットを必要とするようになると、この課題はさらに複雑になります。意図せぬ漏えいを防ぎながら、アプリケーションのシークレットをいかに配布・管理・監視・ローテーションするか——新たな課題が立ち上がります。
前回の記事(第1回)では、AWSとGoogle Cloudのシークレット管理サービス(AWS Secrets Manager、AWS SSM Parameter Store、Google Cloud Secret Manager)を、対象Podに手動で追加した doitintl/secrets-init の initContainer を介して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の Secret や ConfigMap 経由)参照しているものに対して、doitintl/secrets-init ユーティリティを組み込んだ initContainer を追加します。

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 は、指定された名前をもとに環境変数の値を、参照先のシークレット値へと解決します。シークレット名にバージョンを含めれば、特定バージョンのシークレットを参照することも可能です。
PerfectScale™ for Kubernetes
Ready to optimize?
Get your free Kubernetes savings analysis

前提条件
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 Viewer と Secret Manager Secret Accessor の2つを割り当てる方法があります。
GKEクラスターでは、Workload Identity を用いてKubernetes PodにIAMロールを割り当てられます。コンテナを実行しているGCEインスタンスにIAMロールを割り当てる方法もありますが、こちらはセキュリティ面で劣るとされています。
deployment.yaml ファイルの --provider=google フラグのコメントアウトを解除してください。
Webhookのデプロイ
kube-secrets-initwebhookサーバーをデプロイするには、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をフォロー してください。
Your cloud bill shouldn't be a mystery
Optimization, automation, expertise. In one platform.