# 機能設計書 105-証明書管理（certificates）

## 概要

本ドキュメントは、`kubectl certificate` コマンドによる証明書署名要求（CSR）の承認・拒否機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：Kubernetesクラスターにおけるノードやサービスの証明書管理において、CSR（Certificate Signing Request）の承認・拒否はクラスター管理者の重要な責務である。`kubectl certificate` はCSRの状態を変更するための管理インターフェースを提供する。

**機能の利用シーン**：新規ノードのクラスター参加時のCSR承認、kubelet証明書ローテーション時のCSR承認、不正なCSRの拒否、CI/CDパイプラインでの自動承認フローに利用される。

**主要な処理内容**：
1. CSRの取得と状態確認
2. Approve/Deny条件の付与
3. UpdateApproval APIによるCSR状態更新
4. コンフリクト時のリトライ処理

**関連システム・外部連携**：Certificates API（certificates.k8s.io/v1）、証明書署名コントローラー

**権限による制御**：certificates.k8s.io CSRリソースのupdate/approval権限が必要

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 38 | kubectl certificate approve | 主機能 | CSRを承認する |
| 39 | kubectl certificate deny | 主機能 | CSRを拒否する |

## 機能種別

リソース状態管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| サブコマンド | string | Yes | approve または deny | approve / deny のいずれか |
| NAME | string[] | Conditional | CSR名（複数指定可） | ファイルまたは名前で1つ以上のCSR指定必須 |
| -f / --filename | string[] | Conditional | CSR定義ファイル | NAME未指定時は必須 |
| --force | bool | No | 既にapproved/denied状態のCSRも更新 | デフォルト: false |
| -o / --output | string | No | 出力形式 | json/yaml等 |

### 入力データソース

- コマンドライン引数（CSR名）
- マニフェストファイル
- Certificates API（CSR情報取得）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 処理結果 | text | "approved" / "denied" メッセージ |

### 出力先

標準出力（stdout）

## 処理フロー

### 処理シーケンス

```
1. 引数パースとバリデーション
   └─ CSR名またはファイル指定の必須チェック
2. CSRの取得
   └─ CertificateSigningRequests().Get()
3. 条件の確認と更新
   ├─ [approve] DeniedがなければApproved条件を追加
   ├─ [deny] ApprovedがなければDenied条件を追加
   └─ 既に条件がある場合は--forceで強制更新
4. UpdateApproval APIの呼び出し
   └─ CertificateSigningRequests().UpdateApproval()
5. コンフリクト時のリトライ（最大10回）
6. 結果出力
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[CSR名/ファイル取得]
    B --> C[CSRオブジェクト取得]
    C --> D{既にapproved/deniedか}
    D -->|既に反対条件| E[エラー: already approved/denied]
    D -->|既に同一条件| F{--force?}
    F -->|Yes| G[条件再追加]
    F -->|No| H[スキップ]
    D -->|条件なし| I[条件追加]
    G --> J[UpdateApproval呼び出し]
    I --> J
    J --> K{コンフリクト?}
    K -->|Yes, i < 10| C
    K -->|No| L[結果出力]
    H --> L
    L --> M[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-501 | 排他条件 | Approved状態のCSRにDenyを試みるとエラー（逆も同様） | --force未指定時 |
| BR-502 | 冪等性 | 既に同一条件のCSRはスキップ（--force未指定時） | 常に適用 |
| BR-503 | コンフリクトリトライ | UpdateApprovalのコンフリクト時、最大10回リトライ | APIコンフリクト発生時 |
| BR-504 | 条件メッセージ | approve: "This CSR was approved by kubectl certificate approve." | approve時 |
| BR-505 | 条件メッセージ | deny: "This CSR was denied by kubectl certificate deny." | deny時 |
| BR-506 | 条件理由 | approve: "KubectlApprove"、deny: "KubectlDeny" | 常に適用 |

### 計算ロジック

addConditionIfNeeded: 既存のConditionsをスキャンし、反対条件があればエラー、同一条件があれば冪等スキップ、なければ新規追加する。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| CSR取得 | etcd（API Server経由） | SELECT（GET） | CSRの現在状態取得 |
| CSR更新 | etcd（API Server経由） | UPDATE | CSRのApproval状態更新 |

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

UpdateApproval APIを通じてCSRの状態条件を更新する。これにより証明書署名コントローラーが証明書の発行または拒否を実行する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 排他条件エラー | Approved CSRにDeny（またはその逆） | "certificate signing request X is already Approved" |
| - | NotFound | 指定CSRが存在しない | "could not find v1 version of X" |
| - | 未検出 | CSRが1つも見つからない | "No resources found" |
| - | GVK不一致 | CSR以外のリソースが指定された | "can only handle CertificateSigningRequest objects" |

### リトライ仕様

UpdateApproval APIのコンフリクト時、最大10回リトライ（info.Get()で最新状態を再取得してリトライ）。

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

各CSRの更新は個別に実行される。複数CSR指定時は順次処理。

## パフォーマンス要件

特に定義なし。CSR数は通常少数であり、パフォーマンス問題は発生しにくい。

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

- CSRの承認は、発行される証明書がクラスターリソースへのアクセスや特定IDへの認証を付与する可能性があるため、セキュリティ上重要な操作である
- approve/deny権限を持つユーザーを最小限にすべき
- CSRの内容（要求される属性）を承認前に必ず確認すべきである旨がLongDescに記載されている

## 備考

- certificates.k8s.io/v1のみサポート
- LastUpdateTimeは処理実行時のタイムスタンプ（metav1.Now()）が自動設定される
- --force フラグにより、既にapproved/deniedのCSRを再度更新可能

---

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

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

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | CertificateOptions構造体（62-75行目）：コマンドオプション |

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | NewCmdCertificate関数（44-59行目）：親コマンドと2サブコマンド登録 |
| 2-2 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | NewCmdCertificateApprove関数（123-159行目）：approveサブコマンド |
| 2-3 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | NewCmdCertificateDeny関数（171-202行目）：denyサブコマンド |

#### Step 3: メイン処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | modifyCertificateCondition関数（213-277行目）：共通のCSR条件変更処理 |
| 3-2 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | **228-267行目**: CSR取得・条件変更・UpdateApproval・リトライのメインループ |
| 3-3 | certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | addConditionIfNeeded関数（279-306行目）：条件追加ロジック |

**主要処理フロー**:
- **238行目**: CertificateSigningRequests().Get() で型付きオブジェクト取得
- **246行目**: modify関数（addConditionIfNeeded）の呼び出し
- **252行目**: UpdateApproval APIの実行
- **257-262行目**: コンフリクト時のリトライ（最大10回）
- **283-290行目**: 反対条件の存在チェック
- **291-293行目**: 同一条件の冪等性チェック
- **294-301行目**: 新規条件の追加

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

```
NewCmdCertificate
    │
    ├─ NewCmdCertificateApprove
    │      ├─ CertificateOptions.Complete()
    │      ├─ CertificateOptions.Validate()
    │      └─ CertificateOptions.RunCertificateApprove()
    │             └─ modifyCertificateCondition()
    │                    ├─ builder.Unstructured().ResourceNames().Do()
    │                    ├─ certificatesV1Client.Get()
    │                    ├─ addConditionIfNeeded() [Approved条件追加]
    │                    └─ certificatesV1Client.UpdateApproval()
    │
    └─ NewCmdCertificateDeny
           ├─ CertificateOptions.Complete()
           ├─ CertificateOptions.Validate()
           └─ CertificateOptions.RunCertificateDeny()
                  └─ modifyCertificateCondition()
                         ├─ builder.Unstructured().ResourceNames().Do()
                         ├─ certificatesV1Client.Get()
                         ├─ addConditionIfNeeded() [Denied条件追加]
                         └─ certificatesV1Client.UpdateApproval()
```

### データフロー図

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

CSR名/ファイル ──▶ ResourceBuilder ──▶ Visitor
                                          │
API Server ◀── Get() ◀──────────────────┘
       │                                  │
       ▼                                  ▼
   CSRオブジェクト ──▶ addConditionIfNeeded() ──▶ UpdateApproval() ──▶ API Server
                                                                      │
                                                                      ▼
                                                               stdout ("approved/denied")
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| certificates.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates.go` | ソース | メインロジック：approve/deny処理 |
| certificates_test.go | `staging/src/k8s.io/kubectl/pkg/cmd/certificates/certificates_test.go` | テスト | ユニットテスト |
