Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Kubernetesとクラウドのシークレット管理

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

By Alexei LedenevDec 26, 20195 min read
Alexei Ledenev

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

1 yhminsd3pkjvkscqdxvpgq

シークレットは多くの本番システムの運用に欠かせない要素です。意図しないシークレット漏洩は、最優先で対処すべきリスクの一つです。開発者は、アプリケーションのシークレットを守るために最善を尽くす必要があります。

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

Kubernetes Secrets

KubernetesにはSecretというオブジェクトが用意されており、パスワード、SSHキー、APIキー、トークンなど、アプリケーションの機密データを保存できます。Kubernetes Secretは、環境変数として、あるいはファイルとしてマウントする形でPodコンテナに渡せます。Kubernetes Secretsを使えば、機密データや設定をアプリケーションのデプロイから切り離して扱えます。

たとえば、Kubernetes Secretは kubectl create secret コマンドで作成できます:

https://gist.github.com/02c582490747681776f1f480ec2f4165

あるいは、同じシークレットを定義するKubernetesの db-credentials.yaml ファイルでも作成できます:

https://gist.github.com/09d76dd562fb9c5bb6fbaefd9afe377ehttps://gist.github.com/f0de7aa6fa86e29f25a06d78dfeeae5e

ここで注意したいのは、機密データをKubernetes Secretに保存しただけでは安全とは言えないという点です。デフォルトでは、Kubernetes Secrets内のデータはすべて base64 でエンコードされた平文として保存されます。

バージョン1.13以降、Kubernetesは EncryptionConfiguration オブジェクトと組み込みまたは外部の暗号化プロバイダーを使った保存時のSecretsデータ暗号化に対応しています。

現在サポートされている暗号化プロバイダー:

組み込みプロバイダー: aescbcaesgsmsecretbox

KMSプロバイダー:

PerfectScale™ for Kubernetes

Ready to optimize?

Get your free Kubernetes savings analysis

とはいえ、保存時のSecrets暗号化はデフォルトで強制されているわけではありません。さらに、有効化したとしてもそれだけでは不十分で、本格的なシークレット管理ソリューションとは呼べません。

本格的なシークレット管理ソリューションには、シークレットの配布、ローテーション、きめ細かなアクセス制御、監査ログ、利用状況のモニタリング、バージョン管理、強固に暗号化されたストレージ、扱いやすいAPIとクライアントSDK、その他便利な機能が求められます。

クラウドのシークレット管理

多くのクラウドベンダーは、自社プラットフォームの一部としてシークレット管理サービスを提供しており、アプリケーション、サービス、APIへのアクセスに必要なシークレットの保護に役立ちます。これらのサービスを活用すれば、機密情報を平文でハードコードしたり、独自のシークレット管理ライフサイクルを自前で構築したりする必要はありません。きめ細かな権限設定と監査機能を備えており、アプリケーションのシークレットへのアクセスを的確に制御できます。

Kubernetesとシークレット管理サービスの統合

基本的に、どのアプリケーションもベンダー固有のSDK/APIを使えば、シークレット管理サービスに保存されたシークレットにアクセスできます。ただし通常は、アプリケーションコードの変更や、ブートストラップスクリプト、あるいはInit containerを介したクライアントCLIツールやWeb APIの利用が必要になります。

secrets-init ツールでシンプルに

本日、doitintl/secrets-init をリリースしました。クラウドマネージド/セルフマネージドのKubernetesクラスター上で動作するコンテナ化されたworkloadと、cloud-nativeなシークレット管理サービスとの統合をシンプルにする、オープンソースツール(Apache License 2.0)です。

secrets-init の本質は、コンテナ環境内で PID 1 として動作するように設計されたミニマルな init システムである点にあります。dumb-init と同様の役割を果たしながら、複数のcloud-nativeなシークレット管理サービスとスムーズに連携します:

Dockerコンテナにinitシステムが必要な理由

詳しくはYelpの dumb-init リポジトリの解説をご覧ください。

要点は次のとおりです:

  • シグナルの適切な転送
  • 孤児ゾンビプロセスの回収

secrets-init の動作

secrets-initPID 1 として実行され、シンプルなinitシステムとして振る舞います。ENTRYPOINT または最初のコンテナコマンドの位置に入り、子プロセスを起動して、その子プロセスを起点とするセッションへすべてのシステムシグナルを中継します。これがinitプロセスの本質です。一方で secrets-init は、環境変数の_ほぼ_すべてをそのまま引き渡しつつ、特殊な_シークレット変数_だけをシークレット管理サービスから取得した値に置き換えます。

Dockerとの統合

secrets-init は静的にコンパイルされたバイナリ(外部依存なし)で、どんなDockerイメージにも簡単に組み込めます。secrets-init バイナリをダウンロードし、Dockerコンテナの ENTRYPOINT として指定してください。

例:

https://gist.github.com/7efe25155c034ee1b978a2477b3224e4

Your cloud bill shouldn't be a mystery

Optimization, automation, expertise. In one platform.

Kubernetesとの統合

Dockerイメージに手を加えずにKubernetesオブジェクト(Pod/Deployment/Jobなど)で secrets-init を使うには、initContainer 経由で対象のPodに secrets-init を注入する方法がおすすめです。doitint/secrets-init のDockerイメージを利用してもよいですし、独自のイメージを作成しても構いません。initコンテナから共有ボリュームに secrets-init バイナリをコピーし、Podの command を変更して secrets-init が最初に実行されるようにします。

AWS Secrets Managerとの統合

secrets-init をAWS Secrets Managerと組み合わせて使うには、AWSシークレットのARNを環境変数の値として設定します。secrets-init は、指定されたARNをもとに、その環境変数の値を参照先のシークレット値に置き換えます。

Kubernetes Jobで secrets-init を使う例:

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

AWS Systems Manager Parameter Storeとの統合

AWS Systems Manager Parameter Storeは、アプリケーションのパラメータを平文または暗号化(シークレットに近い形)で保存するのにも使えます。

先ほどの例と同様に、AWS Parameter StoreのARNを環境変数の値として設定すれば、secrets-init が指定のARNをもとにその値を参照先のパラメータ値へと置き換えます。

AWS Systems Manager Parameter Storeのフォーマット例:

https://gist.github.com/9a7a83ec1659c391412557e5af340f42

AWS Secrets ManagerおよびParameter StoreからAWSシークレットを解決するには、secrets-init を対象シークレットへのアクセス権限を持つIAMロール配下で実行する必要があります。

これは、Kubernetes PodまたはECS TaskにIAMロールを割り当てることで実現できます。詳しくはEKSブログの記事 Introducing fine-grained IAM roles for service accounts をご覧ください。

コンテナが動作するEC2インスタンス自体にIAMロールを割り当てる方法もありますが、セキュリティ面で大きく劣るため推奨しません。

Google Secret Managerとの統合

Google Cloudは先ごろ、クラウド上でシークレットを管理する新サービス Google Secret Manager をリリースしました。

secrets-init が認識するプレフィックス(gcp:secretmanager:)に続けてシークレット名(projects/{PROJECT_ID}/secrets/{SECRET_NAME} または projects/{PROJECT_ID}/secrets/{SECRET_NAME}/versions/{VERSION})を環境変数の値として指定すれば、secrets-init がその名前をもとに値を参照先のシークレット値へと置き換えます。

https://gist.github.com/65d46eb2b1fe44417a9d91828c94712d

Google Secret ManagerからGoogleシークレットを解決するには、secrets-init を対象シークレットへのアクセス権限を持つIAMロール配下で実行する必要があります。

これは、Workload Identity を使ってKubernetes PodにIAMロールを割り当てることで実現できます。コンテナが動作するGCEインスタンスにIAMロールを割り当てることもできますが、こちらはセキュリティ面で劣ります。

(2020年3月15日)アップデート: Kubernetes Admission Webhook

kube-secrets-init プロジェクトは、Kubernetesの admission webhook を実装したもので、クラウドシークレットへの明示的(環境変数)または暗黙的(Kubernetesの SecretsConfigMaps)な参照を持つPodに対して initContainer を自動で注入します。

関連リンク

まとめ

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

他の記事もお読みになりたい方は、ブログをチェックするか、TwitterでAlexeiをフォローしてみてください。