RustでKMS v2対応のKMSを作ってみた
はじめに
Kagimoriは、Kubernetes向けのシンプルなKey Management System(KMS)です。Kubernetes KMS v2に対応し、ChaCha20-Poly1305とAES-GCM-SIVによる暗号化、エンベロープ暗号化、監査ログ機能を提供します。
Rustで実装されており、パフォーマンスとメモリ安全性を両立しています。また、GPLv3ライセンスで公開しているため、個人開発や小規模プロジェクトでも自由に利用できます。
どうして作ったの?
Kubernetesにおける機密情報管理の課題
Kubernetesでは、APIキーやデータベースパスワードなどの機密情報をSecretリソースとして管理します。しかし、デフォルトではSecretはetcdにBase64エンコードされただけの状態で保存されており、実質的に平文です。
本番環境でSecretなどのリソースを安全に管理するには、暗号化キーを用意することもできますが、外部のKey Management System(KMS)を使った暗号化も可能です[1]。
既存ソリューションの課題
主要なKMSソリューションとして以下があります:
クラウドプロバイダーのKMS
- AWS KMS
- Google Cloud KMS
- Azure Key Vault
これらは高機能で信頼性も高いですが、以下の制約があります。
- 費用: パブリッククラウドなので当然課金される
- クラウドロックイン: 特定のクラウドプロバイダーに依存
- ネットワーク要件: クラウドAPIへのアクセスが必要
オンプレミス・セルフホスト型
- HashiCorp Vault (Enterprise版は有償)
- その他エンタープライズ向けソリューション
これらも優れたソリューションですが
- 複雑性: セットアップと運用が複雑
- 多機能: 非常にありがたいことなのですが、ただ暗号化したいだけの小規模な利用には過剰
- ライセンス: 商用利用に制限がある場合も
個人開発・小規模プロジェクトでの問題
趣味でKubernetesクラスターを運用している開発者や、小規模なプロジェクトでは
- クラウドKMSの費用が気になる
- Vaultのような大規模なシステムは過剰
- シンプルで軽量なソリューションが欲しい
しかし、そのような用途に適したOSSのKMSはあまり存在しませんでした。
なぜGPLv3なのか
KagimoriはGPLv3ライセンスで公開しています。これには以下の理由があります
オープンソースであり続けること
- セキュリティツールは透明性が重要
- コミュニティによる監査が可能
- 自分だけの目では信用できない
- 派生プロジェクトもオープンソースであることを保証
個人・小規模開発での自由な利用
- 費用を気にせず使える
- クラウドプロバイダーに依存しない
- 学習や実験にも自由に利用可能
商用制限ではなく、オープン性の保証
- GPLv3は商用利用も可能
- ただし、Kagimoriを組み込んだ製品もオープンソースにする必要がある
- ネットワーク経由(TCPやUDS)で使用する場合はこの限りではありません
- これにより、エンタープライズベンダーによる「囲い込み」を防ぐ
Protocol Buffersの定義ファイルはApache License 2.0にしており、KagimoriのAPIを利用するクライアントアプリケーションには制約をかけていません。
(KMS v2はもとからApache License 2.0です。Kagimoriで独自定義したAPIもApache License 2.0です)
Kubernetes KMS v2について
KMSとは
Key Management System(KMS)は、暗号化キーの生成、保存、管理を行うシステムです。Kubernetesでは、etcdに保存されるSecretなどのリソースを暗号化するためにKMSを使用できます。
エンベロープ暗号化
Kubernetesが採用しているのはエンベロープ暗号化(Envelope Encryption)という方式です:
- DEK (Data Encryption Key): 実際のデータを暗号化するキー
- KEK (Key Encryption Key): DEKを暗号化するマスターキー
平文データ → DEKで暗号化 → 暗号化データ
DEK → KEKで暗号化 → 暗号化されたDEK
この方式の利点として以下が挙げられます。
- セキュリティ: DEK自体も暗号化されて保存される
- KEKの隔離: マスターキー(KEK)はKMS内に保管
Kubernetesは各SecretごとにKMSに暗号化を依頼します。KMSはキーの生成をリクエストごとに行い、KMS外に出る前にKEKで暗号化します。これにより平文のDEKはKMSの外には出ません。
Kagimoriの設計思想
シンプルさの追求
Kagimoriの設計で最も重視したのはシンプルさです:
- 最小限の依存関係: 必要な機能だけを実装
- 明確な責務: KMSとしての役割に集中
- 簡単なデプロイ: 単一バイナリで動作
「Kagimori(鍵守)」という名前も、シンプルに「鍵を守る」という役割を表現しています。
自分でデプロイする上で依存コンポーネントが多いとデプロイが大変であるため、可能な限りシンプルに使えるようにしました。
対応暗号化アルゴリズム
Kagimoriは2つのAEAD暗号をサポートしています:
ChaCha20-Poly1305
- 高速な暗号化・復号化
- CPUのAES-NI命令がない環境でも高性能
- モバイルやIoTデバイスでの利用に適している
- TLSでも採用されており信頼性も高い
AES-GCM-SIV
- AES-NIがあるCPUでは非常に高速
- より保守的な選択肢
どちらも認証付き暗号化(AEAD)であり、データの機密性と完全性を同時に保証します。
監査ログ
セキュリティシステムにとって監査は重要です。Kagimoriは以下の操作をログに記録します。
- 暗号化/復号のリクエスト
- リクエストしたユーザーID
- リクエスト元のサービス
- タイムスタンプ
これにより、いつ、どのキーが使われたかを追跡できます。
ユーザーIDとサービスはKagimori独自APIで利用可能です。
なぜRustを採用したのか
メモリ安全性とセキュリティ
KMSは機密データを扱うため、セキュリティが最重要です。
Rustを選んだ理由として以下があります。
メモリ安全性
- バッファオーバーフロー、Use-After-Free、データ競合を防ぐ
- ゼロコスト抽象化でパフォーマンスを犠牲にしない
- 暗号化キーが誤ってリークするリスクを低減
型安全性
- コンパイル時に多くのバグを検出
- 暗号化操作のミスをコンパイラが防ぐ
セキュアなライブラリ
-
ring
、RustCrypto
など、監査されている暗号ライブラリ -
zeroize
でメモリ上の機密データを確実に消去
パフォーマンス
KMSは暗号化操作を高速に実行する必要があり、
- C/C++並みの性能: ゼロコストの抽象化
- 並行処理: Tokioによる効率的な非同期I/O
- 低レイテンシ: ガベージコレクションなし
これらの特徴を持つRustはこのシステムにおいて好ましい言語であると考え採用しました。
エコシステムの利点
Rustのエコシステムは、KMS開発を始めとしたバックエンドの処理や、暗号化において強みがあります。
gRPC/Protocol Buffers
-
tonic
: Rust製の高性能gRPCライブラリ -
prost
: Protocol Buffersのコード生成
暗号化
-
ring
: 暗号ライブラリ -
chacha20poly1305
、aes-gcm-siv
: 実装が充実
非同期ランタイム
-
tokio
: 高性能な非同期ランタイム - 多数の同時接続を効率的に処理
開発体験
Rustは学習曲線が急ですが、一度習得すれば:
- 安心感: コンパイルが通れば、多くのバグは既に排除されている
- リファクタリング: 型システムがリファクタリングをサポート
セキュリティクリティカルなシステムでは、この「コンパイラが守ってくれる」安心感は大きな価値があります。
技術的な実装
アーキテクチャ概要
Kagimoriは以下のコンポーネントで構成されています:
- server: Kubernetes KMS v2プロトコルの実装
- encryption: 暗号化/復号化ロジック
- audit-log: 監査ログの記録
エンベロープ暗号化の実装
Kubernetesから暗号化リクエストが来た際は以下のようなフローで処理が行われます。
- DEKを生成
- 暗号化処理
- ログを残す
- DEKを暗号化
- レスポンスを返す
レスポンスを返す際には暗号化されたDEKとデータを返します。
逆に復号を行う際は暗号化されたDEKとデータが渡されます。その処理は以下のフローで行われます。
- DEKを復号
- 復号したDEKで暗号化されたデータを復号
- 平文のデータを返す
エンベロープ暗号化では、暗号化と復号の処理の間、ネットワーク上には平文のDEKは全く登場しません。
鍵まで暗号化し、その鍵も使い捨ての鍵であるため一つのDEKが漏れたとしてもそれ以外のデータには影響しないという特徴があります。
監査ログの設計
監査ログはJSON Lines形式で出力されます。
これにより以下の利点があります。
-
解析が容易:
jq
などのツールで処理可能 - ログ集約: ログ基盤との統合が簡単
開発で苦労したポイント
まずKMSの理解
まず「KubernetesのSecretって暗号化されてないのマジ?」という軽い気持ちから始まっているので、KMSとはなんぞやというところからのスタートでした。
その時はエンベロープ暗号化というのは名前は聞いたことがあるやつ程度の認識でしたが、資料を読んだりLLMに聞いたりして理解を深めていきました。
理解が浅かったことが原因で、KMS v2のフィールド (特にannotations
) の意味がわからず非常に苦労しました。
そんな状態でセキュリティツールを作るなという批判は、もっともな意見でぐうの音も出ないですが、大目に見てください。
テスト
Kubernetesで使用するのでKubernetesで動くことを確認できなければ怖いということで、Kubernetesとの結合テストを書くのに非常に苦労しました。
KMS v2はどうやらUnix domain socketしか受け入れてくれないらしく、Kubernetesクラスタ内でkagimoriを立てるということに非常に苦労しました。
今後の展望
追加できたら良いなの機能
キーローテーション
- KEKの自動定期的ローテーション
- 自動/手動ローテーションの選択
HSMの利用
- Hardware Security Module対応
- より高度なキー保護
メトリクス
- Prometheusメトリクスのエクスポート
- 暗号化/復号化のレイテンシ
- エラー率の監視
コミュニティへの期待
Kagimoriは非常に荒削りなプロジェクトです。以下の形で貢献いただけると嬉しいです:
フィードバック
- 使ってみた感想
- バグレポート
- 機能リクエスト
コントリビューション
- コードの改善
- ドキュメントの充実
- 他の暗号化アルゴリズムの追加
セキュリティレビュー
- コードレビュー
- 脆弱性の報告
- ベストプラクティスの提案
特にセキュリティに関するフィードバックは大歓迎です。多くの目でレビューされることが、セキュリティソフトウェアの品質向上につながります。
まとめ
Kagimoriは、個人開発や小規模プロジェクトでKubernetesのSecretを安全に管理するためのシンプルなKMSです。
単純に暗号化と復号を提供する単体のシステムとしても利用可能です。そのためのKMS v2ではないAPIも用意しています (KMS v2とあんまり変わんなくない?となりそうですが)。
特徴:
- Kubernetes KMS v2対応
- Rust製で高速かつ安全
- GPLv3ライセンスで自由に利用可能
- シンプルな設計で理解しやすい
こんな人におすすめ:
- 趣味でKubernetesを運用している
- クラウドKMSの費用が気になる
- シンプルなKMSソリューションが欲しい
- セキュリティを学びたい
ぜひ試してみてください!
フィードバックや貢献をお待ちしています!
この記事はAIの助けを大いに借りて執筆しました。
数回読み直し、自分で説明できない部分や間違っている部分は削除/訂正していますが、気づかなかった部分が残っている場合があります。
もし、間違い等にお気づきの場合は優しく教えていただけると幸いです。
Discussion