はじめに
こんにちは、SRE部ECプラットフォーム基盤SREブロックの織田です。普段は主にZOZOTOWNのリプレイスやインフラを改善、運用しています。
本記事では、Secret管理コンポーネントであるKubernetes External Secrets(以降、KESと表記)の非推奨を受けて、どのような対応を実施したのか紹介します。
目次
- はじめに
- 目次
- なぜSecret管理コンポーネントを利用するのか?
- Kubernetes External Secrets(KES)について
- 移行先の選定
- External Secrets Operator(ESO)について
- 移行における注意点や変更点
- 移行の実施
- 最後に
なぜSecret管理コンポーネントを利用するのか?
Secret管理コンポーネントとは、KubernetesのSecretを管理する機能を持つソフトウェアのことです。
Kubernetesを運用する上でSecret管理コンポーネントを利用しない場合は、Secret manifestをKubernetesにapplyしSecretを作成することになるかと思います。KubernetesのSecretは、データをbase64エンコードしているだけなので、誰でもbase64デコードができ、データを確認できます。そのため、Secret manifestのような基本的に秘匿情報を含むファイルは、GitHubのようなバージョン管理システムにコミットするべきではありません。
コミットを避ける方法の1つとして、Secret管理コンポーネントの利用が挙げられます。そうすることでAWS Secrets ManagerやAzure Key VaultのようなSecret Management System(以降、SMSと表記)に登録された秘匿情報をKubernetesが取得し、Secretに注入できます。その結果、Secret manifestをバージョン管理システムにコミットせず、安全にデータを扱うことが可能です。
弊チームではこれまでSecret管理コンポーネントとしてKESを使用していました。
Kubernetes External Secrets(KES)について
KESとは?
KubernetesのSecretリソースを管理するオペレーターです。弊チームでは外部のSMSからデータを取得し、取得したデータをKubernetesのSecretへ注入するために利用しています。
KESを使ったKubernetes構成
弊チームではどのような構成でKESを利用していたのか紹介します。下図がKESを採用していたおおよそのKubernetesの構成図です。
KESがExternalSecretの内容をもとにAWS Secrets Managerに登録されているデータを取得し、Secretを作成します。 Application(Deployment,Cronjob,etc.)は、ExternalSecretが作成したSecretを参照したり、volumeとしてマウントします。
このようにSMSから取得したデータをKubernetesで利用することによってSecret manifestをコミットせずに済むため、よりセキュアに扱うことが可能です。
KESの非推奨について
2021/11/03にKESは非推奨化が発表され、現在はアーカイブされています。
KESが非推奨になった背景としては、アクティブなメンテナが存在していなかったため、プロジェクト内の問題を引き起こしている技術的負債が解消されず、メンテナンスされていないことだとKES is deprecated, migrate to ESO!で言及されています。
発表の内容を見るとOSSをメンテナンスすることはモチベーションの維持や管理の面においてとてもハードだと感じるとともに、今まで利用させていただき感謝しかありません。
ただ弊チームのKubernetes Clusterでは、全SecretをKESで生成しているため、なにかしらの対応をとる必要がありました。
移行先の選定
ここからは移行先コンポーネントの選定について具体的に説明します。
優先事項の決定
まずは移行先を決めるにあたって、比較する項目を決め以下の4つを優先事項としました。
- Kubernetes manifestやkustomizeの構成に変更が少ないこと
- Secret更新時の運用に変更が少ないこと
- 移行コストが少ないこと
- KESで利用している機能、または同等の機能が使えること
- ある程度アクティブに活動があるOSSであること
現状、KESに不満はないため、kustomize構成やSecret運用に大きな変更を加えず、移行コストを抑えたいと考えました。
KESで利用している機能は、Secretの更新タイミングをコントロールできるもの(自動更新のOFF)です。自動更新をONにしているとSMSを更新後、Secretも自動更新されてしまうため、リリースタイミングをコントロールしたいと考え、自動更新をOFFにしています。Secretを更新してもPodを再起動しなければ更新後の値を読み取りませんが、タイミング悪くPodが再起動されてしまった場合意図せず読み込んでしまうため、このような対応をしています。
移行先の検討、比較
次に移行先の検討です。アクティブに開発されていそうな以下3つのコンポーネントを検討し、比較しました。
External Secrets Operator(以降、ESOと表記)は、KESを開発していたオーガナイゼーション(External Secrets)が開発しています。JavaScriptで書かれていたKESをGoでリファクタリングしたコンポーネントです。ExternlSecretのapiVersionは変更になっていますが、ExternalSecretがSecretを作成するということは変わっていないため、Kubernetes manifestの変更は少なく済みそうです。KESの非推奨issueでもESOへの移行を勧められているのとKESからESOへの移行ツール(以降、移行ツールと表記)が用意されています。そのため、移行コストについても少なく済みそうだと考えました。
Secets Store CSI Driverは(以降、CSI Driverと表記)、Kubernetes SIGsが開発しています。名前の通り、Container Storage Interface(CSI)を利用し、シークレットやキー、証明書をPodにVolumeとしてマウントします。また、マウントしたものをSecretに同期したり、複数のSecretオブジェクトを1つのVolumeとしてマウントするなど様々な機能があります。Podにシークレットやキー、証明書をVolumeとしてマウントした上でSecretに同期する必要があることを考えると、少なくともKubernetes manifestへのインパクトは大きそうです。
Sealed Secretsは、Bitnamiが開発していて、"全Kubernetes configをGitで管理できるようにする" ことを目的に作成されました。SecretをSealed Secretsに暗号化させ、Kubernetes manifestを生成します。Kubernetesで動作するコントローラのみが復号化でき、原作者でさえもSealedSecretからオリジナルのSecretを取得できません。そのため、Public repositoryにコミットしても安全に保管できると言われています。1
この段階で移行先がほぼ決まっている感じはありますが、候補とした3つを比較しました。2
比較項目\コンポーネント | ESO | CSI Driver | Sealed Secrets |
---|---|---|---|
Kubernetes manifest変更の少なさ | ◎ | ✗ | △ |
移行コストの少なさ | ◎ | ✗ | ○ |
Secret運用への影響の少なさ | ◎ | ✗ | ○ |
累計コミット数 | 2011 | 1062 | 996 |
自動更新OFF/ON機能 | ○ | - | △ |
移行先の決定
比較の結果、移行先は優先事項を全て満たしていたESOに決定しました。比較表を見ると一目瞭然ですが、不採用としたコンポーネントごとの理由としては以下になります。
- CSI Driverは、ほかのコンポーネントと比べKubernetes manifestに大きな変更が必要で、それに伴い移行コストや運用変更コストも多そうだと判断したため
- Sealed Secretsは、SMSを利用できないこと、暗号化した秘匿情報をバージョン管理システムにコミットするのは可能であれば避けたかったため
移行コストやKubernetes manifestの変更コストを優先事項に挙げるとKESの後継であるESOを選ぶのは必然だったのかと思いました。
External Secrets Operator(ESO)について
移行先を決めたのでESOについて見ていきたいと思います。
ESOは、Kubernetesオペレータで外部のSMSから情報を読み取り、その値をKubernetes Secretに自動的に注入します。目的は、SMSとKubernetes Secretを同期させることです。
ESOのアーキテクチャ
全体像としては、下図のようになっています。
Kubernetesをカスタムリソース(CR)で拡張し、ExternalSecretにSecretの保存場所と同期方法を定義することで、外部のSMSからデータを取得しSecretにデータを注入します。参照しているSMSが変更された場合、Kubernetes Clusterの状態を確認し、それに応じてSecretを更新します。
より詳細な情報については、External Secrets Operatorの公式ドキュメントをご確認ください。
移行における注意点や変更点
移行方法の紹介の前にKESからESOへの移行において、把握しておくべき変更点や注意点を確認します。
- API追加に伴うアーキテクチャの変更
Kind:ExternalSecret
のapiVersion変更- KESからESOへ移行する際に注意すること
1つ目はAPI追加に伴うアーキテクチャの変更です。KESとESOはカスタムAPIの数が異なり、以下の表の様になっています。
コンポーネント | API |
---|---|
KES | ExternalSecret |
ESO | ExternalSecret, SecretStore, ClusterSecretStore, ClusterExternalSecret |
KESでは、前述の通りExternalSecretの設定をもとにSMSからデータを取得し、Secretに注入します。ESOでは、新たにSecretStore,ClusterSecretStore,ClusterExternalSecretが追加され、基本的なアーキテクチャとしては下図のようになっています。
ESOは、SecretStoreまたはClusterSecretStoreに格納された情報を使い、外部のSMSに接続しExternalSecretの設定をもとにデータを取得します。無事、SMSとExternalSecretが同期できていれば、取得したデータを注入したSecretが作成されます。というようにSMSとExternalSecretの間にSecretStoreが追加されました。SecretStoreはnamespaceスコープで、ClusterSecretStoreはclusterスコープです。ExternalSecretとClusterExternalSecretも同様です。そのため、移行する際には新しくSecretStoreを作成する必要があります。
2つ目は、Kind:ExternalSecret
のapiVersion変更についてです。KESではkubernetes-client.io/v1
でしたが、ESOではexternal-secrets.io/v1beta1
に変更されています。apiVersionが変わりそれに伴いスキーマも変更になっているため、例えばKESではDeploymentで定義していたデータ取得のポーリング間隔をESOではExternalSecretで定義します。他にも変更になった点があるため、事前に確認が必要です。
ESOへ移行するにあたってどのような変更をしたらよいかについては、公式ドキュメントのExternalSecretのページをご確認ください。
3つ目は、KESからESOへ移行する際の注意点です。Upgrade from KES to ESOでKESとESOではいくつか非互換性があるため、かなり厄介だと述べられています。移行ツールは、非互換性に関してほぼカバーされているとのことですが、移行ツールでは、SecretStoresがKESのService Accountを指定するようになっているため、移行後にKESをアンインストールする予定がある場合は、調整する必要があるとのことです。
移行の実施
ここからは、実際にどのように移行したか紹介します。
移行方法
まずは、移行方法についてです。前提として、今回の移行ではExternalSecret、Secretを既存の名前とは異なる名前で再作成しています。そのため、既存Secret名をそのまま利用したい場合は、以下の手順ではエラーになってしまいますのでご注意ください。
まずは、ESOのドキュメントを見てアーキテクチャを理解しながら移行手順を考えました。幸いなことに移行ツールが用意されていたため、テスト環境で移行ツールを実行したり、手動移行を参考にし、移行手順を作成しました。
次に、考えた移行手順を検証し、システムに影響がなく可能な限り作業量の少ない方法を試行錯誤しながら移行手順をブラッシュアップしました。システムに影響を与えないことは必須だと思いますが、弊チームの場合、Secretの切り替え作業が1回では済まないためできるだけ作業量を減らせるよう努力しました。
それらを踏まえた移行手順が以下になります。
- ESO(CRD,Deployment,ServiceAccount,etc.)をデプロイ
- SecretStore,ExternalSecret(ESO)を作成
- ExternalSecret(KES)を削除
- KES(CRD,Deployment,ServiceAccount,etc.)の削除
各手順について少しずつ触れたいと思います。
ESO(CRD,Deployment,ServiceAccount,etc.)をデプロイでは、カスタムAPIリソース以外をデプロイしました。CRDがKubernetesに登録されていない状態でExternalSecretなどのカスタムAPIリソースを作成しようとするとエラーになるためです。
SecretStore,ExternalSecret(ESO)を作成では、CRD作成後、カスタムAPIリソースをデプロイしました。このタイミングでSecretStore、ExternalSecret、Secretが作成されます。また、KESのExternalSecretをもとに作成されているSecretを参照しているリソース(Deployment,CronJob,etc.)はここでESOのものに切り替えました。KESとESOでは、ExternalSecretのapiVersionが異なるため、作成時の重複についてあまり気にする必要はありません3が、より安全に行いたい場合は、KES Deploymentのreplicasを0にしておくことで予期せぬExternalSecretの再作成を防ぐことができます。
ExternalSecret(KES)を削除では、手順2で切り替え、参照されなくったExternalSecretを削除しました。
KES(CRD,Deployment,ServiceAccount,etc.)の削除では、不要になったKES関連のリソースの削除しました。
より安全な移行が求められる場合は、Manual Migrationで示されている手順を実施することで解決ができるかと思います。
工夫したポイント
最後になりますが、非推奨の対応で工夫したポイントを2つ紹介したいと思います。
1つ目は、移行手順の策定において公式が用意していた移行ツールを参考にし、安全な移行方法を決定しました。移行用ツールが用意されているのでそちらを利用すればよさそうではあるのですが、以下の理由で利用しませんでした。
- 移行ツールを利用するには、ツールを修正する必要があった
- 移行ツールで生成したmanifestを変更するより、現状のmanifestを変更したほうが作業量を少なく済ませられた
- Upgrade from KES to ESOで言われている通り、移行ツールを実行しても手作業が発生するため(手順のみ参考にさせていただいた)
2つ目に、ESOのリソースとKESのリソースでnameやlabelsなどにおいて名前を被らせないようにしました。どちらもデフォルトの状態で利用しようとするといろいろなリソース名(Deployment,ServiceAccount,etc.)がバッティングしてしまいます。
例えば、ServiceAccountのリソース名はどちらもexternal-secrets
です。ESOをデプロイするタイミングでKESのSAが更新されてしまい、KESをアンデプロイするタイミングでESOも利用しているSAが削除されてしまいます。そのため、KESが利用している名前とはかぶらないように調整し、ESOをデプロイしました。
最後に
本記事では、KESの非推奨対応についてどのようなことを実施したか、具体的に紹介しました。結果として、KESの非推奨対応を行い、ESOに移行することでSecretを管理する重要なコンポーネントで問題が起きる前に対応できました。
また、ESOを調べることで新機能やアーキテクチャの変化によって、Secretをよりセキュアに扱えることや現状抱えているkustomizeのSecret構成を改善できることがわかりました。しかし、今回の対応ではそこまで踏み込んだ対応できていないため、次のステップではそれらの対応を実施すると共にSREとしてトイルを削減したいと考えています。
ZOZOでは、一緒にサービスを作り上げてくれる方を募集中です。ご興味のある方は、以下のリンクからぜひご応募ください!
- https://github.com/bitnami-labs/sealed-secrets#sealed-secrets-for-kubernetes↩
- 2022年10月20日現在↩
- 前提として、KESとESOのExtenalSecretとSecretは別名で作成すること↩