# 機能設計書 160-暗号化プロバイダー

## 概要

本ドキュメントは、Key Management Serviceとの統合によるSecret等のリソース暗号化を提供する「暗号化プロバイダー」機能の設計について記述する。

### 本機能の処理概要

**業務上の目的・背景**：Kubernetesクラスターでは、Secret等の機密データがetcdに保存される。デフォルトではBase64エンコードのみで暗号化されないため、etcdに直接アクセスされた場合にデータが露出するリスクがある。KMS（Key Management Service）プロバイダーは、外部のKMSサービスと連携してetcdに保存されるデータの暗号化・復号を行うことで、データの機密性を保護する。

**機能の利用シーン**：kube-apiserverがSecretやConfigMapなどのリソースをetcdに書き込む際に暗号化する場合、etcdからリソースを読み込む際に復号する場合。AWS KMS、Azure Key Vault、HashiCorp Vault等の外部KMSサービスと統合する場合に利用される。

**主要な処理内容**：
1. Encrypt RPC：平文データの暗号化リクエストを外部KMSプラグインに送信
2. Decrypt RPC：暗号文の復号リクエストを外部KMSプラグインに送信
3. Status RPC：KMSプラグインの健全性チェックとキーIDの取得
4. gRPCサーバーフレームワーク（GRPCService）の提供
5. v2とv1beta1の2つのAPIバージョンをサポート

**関連システム・外部連携**：外部KMSプラグイン（gRPCサーバー）、kube-apiserver（gRPCクライアント）、etcd（暗号化データの保存先）。

**権限による制御**：KMSプラグインはUnix Domain Socket経由でローカル通信するため、ノードレベルのアクセス制御が適用される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | バックエンドgRPCサービスのため関連画面なし |

## 機能種別

データ連携 / セキュリティ / 暗号化

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| EncryptRequest.plaintext | bytes | Yes | 暗号化対象の平文データ | 空でないこと |
| EncryptRequest.uid | string | Yes | リクエストの一意識別子 | 空でないこと |
| DecryptRequest.ciphertext | bytes | Yes | 復号対象の暗号文 | 空でないこと |
| DecryptRequest.uid | string | Yes | リクエストの一意識別子 | 空でないこと |
| DecryptRequest.key_id | string | Yes | 暗号化時に使用されたキーID | 空でないこと |
| DecryptRequest.annotations | map<string, bytes> | No | 暗号化時に付与されたメタデータ | FQDNキー、合計32kB未満 |

### 入力データソース

kube-apiserverからのgRPCリクエスト

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| EncryptResponse.ciphertext | bytes | 暗号化されたデータ（1kB未満） |
| EncryptResponse.key_id | string | 暗号化に使用されたキーID（1kB未満） |
| EncryptResponse.annotations | map<string, bytes> | 暗号化メタデータ（キー+値合計32kB未満） |
| DecryptResponse.plaintext | bytes | 復号された平文データ |
| StatusResponse.version | string | KMS gRPCプラグインAPIバージョン（v2/v2beta1） |
| StatusResponse.healthz | string | 健全性状態（"ok"以外は異常） |
| StatusResponse.key_id | string | 現在の書き込みキーID |

### 出力先

gRPCレスポンスとしてkube-apiserverに返却

## 処理フロー

### 処理シーケンス

```
1. kube-apiserver起動時
   └─ KMSプラグインとのgRPC接続確立、Status RPCで健全性確認
2. リソース書き込み（暗号化）
   └─ Encrypt RPCで平文を暗号化し、暗号文+keyID+annotationsをetcdに保存
3. リソース読み込み（復号）
   └─ etcdから暗号文+keyID+annotationsを取得し、Decrypt RPCで復号
4. 定期的な健全性チェック
   └─ Status RPCをポーリングしてKMSプラグインの状態を監視
```

### フローチャート

```mermaid
flowchart TD
    A[リソース書き込み] --> B[Encrypt RPC呼び出し]
    B --> C[暗号文 + keyID + annotations受信]
    C --> D[etcdに暗号化データ保存]

    E[リソース読み込み] --> F[etcdから暗号化データ取得]
    F --> G[Decrypt RPC呼び出し]
    G --> H[平文データ受信]
    H --> I[APIレスポンスとして返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-160-1 | 暗号文サイズ制約 | ciphertextは空でなく1kB未満 | Encrypt RPC |
| BR-160-2 | キーIDサイズ制約 | key_idは空でなく1kB未満 | Encrypt/Status RPC |
| BR-160-3 | アノテーションキー制約 | アノテーションキーはFQDN（RFC 1123準拠） | Encrypt RPC |
| BR-160-4 | アノテーションサイズ制約 | キー+値の合計は32kB未満 | Encrypt RPC |
| BR-160-5 | バージョン互換 | versionフィールドはv2またはv2beta1（両方同等） | Status RPC |
| BR-160-6 | 健全性判定 | healthzが"ok"以外の場合はプラグイン異常 | Status RPC |
| BR-160-7 | キーローテーション | key_idの変化によりデータの陳腐化を検出 | Status RPC |

### 計算ロジック

特になし。暗号化/復号はKMSプラグインに委譲される。

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 暗号化書き込み | etcd (secrets等) | INSERT/UPDATE | 暗号化されたデータをetcdに保存 |
| 復号読み込み | etcd (secrets等) | SELECT | etcdから暗号化データを取得し復号 |

### テーブル別操作詳細

etcdへのデータ保存はkube-apiserverのストレージ層が管理する。KMSプラグインはデータの暗号化/復号のみを担当する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | gRPC接続エラー | KMSプラグインプロセスが停止 | プラグインの再起動 |
| - | 暗号化エラー | KMSバックエンドのキーエラー | KMSバックエンドの状態確認 |
| - | 復号エラー | 暗号化時と異なるキー | キーローテーション状態の確認 |
| - | 健全性エラー | healthzが"ok"以外 | KMSプラグインの状態確認 |

### リトライ仕様

Status RPCはポーリングによる定期確認で自動リトライされる。Encrypt/Decrypt RPCの失敗はAPIリクエストの失敗として返却される。

## トランザクション仕様

gRPCの単一RPC呼び出しが1トランザクション。暗号化/復号はetcd書き込み/読み込みと連動するが、アトミックではない。

## パフォーマンス要件

Encrypt/Decrypt RPCはリソースアクセスのクリティカルパスにあるため、低レイテンシが求められる。gRPCサーバーは接続タイムアウトを設定可能。

## セキュリティ考慮事項

- 平文データはgRPC通信を通じてKMSプラグインに送信される（Unix Domain Socketのためローカル通信）
- 暗号化キーはKMSバックエンド（HSM、クラウドKMS等）で安全に管理される
- annotationsはetcdに平文で保存されるため、機密情報をannotationsに含めてはならない
- キーローテーション時は古いキーで暗号化されたデータの再暗号化が必要

## 備考

- v2（推奨）とv1beta1の2つのAPIバージョンが存在
- v2とv2beta1は同等のAPI
- KMSプラグインはGRPCServiceフレームワークを使って実装できる
- Unix Domain Socketベースのローカル通信

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造（gRPCプロトコル定義）を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | api.proto (v2) | `staging/src/k8s.io/kms/apis/v2/api.proto` | v2のgRPCサービスとメッセージ定義 |
| 1-2 | api.proto (v1beta1) | `staging/src/k8s.io/kms/apis/v1beta1/api.proto` | v1beta1のプロトコル定義 |

**読解のコツ**: **24-32行目**でKeyManagementServiceサービスが3つのRPC（Status, Decrypt, Encrypt）を定義。**36-46行目**でStatusResponse（version, healthz, key_id）を定義。**48-58行目**でDecryptRequest（ciphertext, uid, key_id, annotations）を定義。**65-90行目**でEncryptRequest/Responseを定義。constraintsは全てprotoコメントに記載されている。

#### Step 2: Serviceインターフェースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | interface.go | `staging/src/k8s.io/kms/pkg/service/interface.go` | KMS Serviceインターフェース定義 |

**主要処理フロー**:
- **22-29行目**: Service インターフェースでDecrypt/Encrypt/Statusの3メソッドを定義
- **32-36行目**: EncryptResponse型（Ciphertext, KeyID, Annotations）
- **39-43行目**: DecryptRequest型（Ciphertext, KeyID, Annotations）
- **46-50行目**: StatusResponse型（Version, Healthz, KeyID）

#### Step 3: gRPCサーバー実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | grpc_service.go | `staging/src/k8s.io/kms/pkg/service/grpc_service.go` | GRPCService実装 |

**主要処理フロー**:
- **30-37行目**: GRPCService構造体（addr, timeout, server, kmsService）
- **42-53行目**: NewGRPCServiceでインスタンス生成
- **57-72行目**: ListenAndServeでUnix Domain Socket上のgRPCサーバーを起動。**64行目**でConnectionTimeout設定、**69行目**でKeyManagementServiceServerを登録
- **91-102行目**: Status RPCの実装（kmsService.Statusに委譲）
- **105-118行目**: Decrypt RPCの実装（kmsService.Decryptに委譲）
- **121-132行目**: Encrypt RPCの実装（kmsService.Encryptに委譲）

#### Step 4: ユーティリティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | util.go | `staging/src/k8s.io/kms/pkg/util/util.go` | ソケットパス等のユーティリティ |

### プログラム呼び出し階層図

```
GRPCService (gRPCサーバー)
    |
    +-- ListenAndServe() (Unix Domain Socketでリッスン)
    |      +-- grpc.NewServer()
    |      +-- RegisterKeyManagementServiceServer()
    |      +-- gs.Serve()
    |
    +-- Status() -> kmsService.Status()
    +-- Encrypt() -> kmsService.Encrypt()
    +-- Decrypt() -> kmsService.Decrypt()
    |
    +-- Shutdown() -> server.GracefulStop()
    +-- Close() -> server.Stop()
```

### データフロー図

```
[入力]                       [処理]                          [出力]

平文データ ──────────> GRPCService.Encrypt() ──────> 暗号文 + keyID + annotations
(kube-apiserver)        (kmsService.Encrypt)          (etcdに保存)

暗号文 + keyID ──────> GRPCService.Decrypt() ──────> 平文データ
(etcdから読み込み)      (kmsService.Decrypt)          (APIレスポンス)

(なし) ──────────────> GRPCService.Status() ────────> version + healthz + keyID
                        (kmsService.Status)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| api.proto (v2) | `staging/src/k8s.io/kms/apis/v2/api.proto` | プロトコル定義 | v2 gRPCサービス定義 |
| api.proto (v1beta1) | `staging/src/k8s.io/kms/apis/v1beta1/api.proto` | プロトコル定義 | v1beta1 gRPCサービス定義 |
| api_grpc.pb.go (v2) | `staging/src/k8s.io/kms/apis/v2/api_grpc.pb.go` | 生成コード | v2 gRPCクライアント/サーバー |
| api.pb.go (v2) | `staging/src/k8s.io/kms/apis/v2/api.pb.go` | 生成コード | v2 Protobufメッセージ型 |
| v2.go | `staging/src/k8s.io/kms/apis/v2/v2.go` | ソース | v2 パッケージ補助 |
| interface.go | `staging/src/k8s.io/kms/pkg/service/interface.go` | ソース | KMS Serviceインターフェース |
| grpc_service.go | `staging/src/k8s.io/kms/pkg/service/grpc_service.go` | ソース | gRPCサーバーフレームワーク |
| util.go | `staging/src/k8s.io/kms/pkg/util/util.go` | ソース | ユーティリティ関数 |
| plugin.go | `staging/src/k8s.io/kms/internal/plugins/_mock/plugin.go` | ソース | モックプラグイン実装 |
