# 機能設計書 70-Sysctl管理

## 概要

本ドキュメントは、Kubeletにおけるsysctlパラメータのホワイトリスト管理とPod Admission制御機能の設計を記述する。

### 本機能の処理概要

Sysctl管理機能は、PodのSecurityContextで指定されたsysctlパラメータが安全（名前空間分離されている）であるかを検証し、許可されていないsysctlを使用するPodのAdmissionを拒否するコンポーネントである。

**業務上の目的・背景**：Linuxのsysctlパラメータはカーネルの動作を変更できるが、名前空間分離されていないsysctlを変更するとノード全体に影響が及ぶ。Sysctl管理機能は、カーネルバージョンに応じた安全なsysctlのリストを動的に生成し、安全でないsysctlの使用を防止する。

**機能の利用シーン**：(1) PodのSecurityContextでsysctlを指定した場合のAdmissionチェック、(2) カスタム許可リストによる追加sysctlの許可、(3) hostNetworkやhostIPCを使用するPodでの名前空間制約チェック。

**主要な処理内容**：
1. カーネルバージョンに基づく安全なsysctlホワイトリストの動的生成
2. カスタム許可パターン（ワイルドカード対応）のバリデーションと登録
3. PodAdmission時のsysctlバリデーション（安全性チェック、NameSpace制約チェック）

**関連システム・外部連携**：Linux Kernel（sysctlの名前空間分離情報）、Lifecycle Manager（PodAdmitHandler Chain）。

**権限による制御**：Kubelet設定（--allowed-unsafe-sysctls）でカスタム許可リストを制御。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はCLI画面との直接的な関連はなく、Kubelet内部コンポーネントとして動作する |

## 機能種別

セキュリティ管理（Sysctl Admission制御）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| patterns | []string | No | カスタム許可sysctlパターン（ワイルドカード末尾可） | IsValidSysctlPatternに準拠、SysctlMaxLength以下 |
| attrs | *PodAdmitAttributes | Yes (Admit) | PodAdmission属性 | pod.Spec.SecurityContext.Sysctlsが設定済み |

### 入力データソース

- Kubelet設定: --allowed-unsafe-sysctls フラグ
- カーネルバージョン: utilkernel.GetVersion()
- Pod Spec: SecurityContext.Sysctls

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| PodAdmitResult | lifecycle.PodAdmitResult | Admit=true/false、Reason=SysctlForbidden |
| SafeSysctlAllowlist | []string | カーネルバージョンに基づく安全sysctlリスト |

### 出力先

- Lifecycle Manager: PodAdmitResult（Podの受け入れ/拒否判定）

## 処理フロー

### 処理シーケンス

```
1. SafeSysctlAllowlist生成（Kubelet起動時）
   └─ カーネルバージョン取得 → 各sysctlの最小カーネルバージョンチェック → リスト生成
2. NewAllowlist（カスタム許可リスト構築）
   └─ パターンバリデーション → 名前空間チェック → sysctls/prefixesマップ登録
3. Admit（PodAdmission時）
   └─ SecurityContext.Sysctlsの各エントリをvalidateSysctlで検証
4. validateSysctl（個別sysctl検証）
   └─ 完全一致チェック → プレフィックスマッチ → hostNet/hostIPC制約チェック
```

### フローチャート

```mermaid
flowchart TD
    A[Pod Admission] --> B{SecurityContext.Sysctls設定あり?}
    B -->|No| C[Admit=true]
    B -->|Yes| D[各sysctlをvalidateSysctl]
    D --> E{許可リストに存在?}
    E -->|No| F[Admit=false: SysctlForbidden]
    E -->|Yes| G{hostNetworkとIPCNamespaceの競合?}
    G -->|Yes| H[Admit=false: SysctlForbidden]
    G -->|No| I{hostIPCとIPCNamespaceの競合?}
    I -->|Yes| J[Admit=false: SysctlForbidden]
    I -->|No| K[次のsysctlへ]
    K --> L{全sysctl検証完了?}
    L -->|No| D
    L -->|Yes| M[Admit=true]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-70-01 | 名前空間分離必須 | 許可されるsysctlは名前空間分離されている（IPC/NET）もののみ | 常時 |
| BR-70-02 | カーネルバージョン制約 | 一部のsysctlは特定カーネルバージョン以降でのみ安全 | 安全リスト生成時 |
| BR-70-03 | hostNetwork制約 | NET名前空間のsysctlはhostNetwork=trueのPodでは使用不可 | Admission時 |
| BR-70-04 | hostIPC制約 | IPC名前空間のsysctlはhostIPC=trueのPodでは使用不可 | Admission時 |
| BR-70-05 | ワイルドカード対応 | パターン末尾の"*"はプレフィックスマッチとして処理される | カスタム許可リスト |
| BR-70-06 | UnknownNamespace拒否 | 名前空間が不明なsysctlはカスタム許可リストに追加不可 | NewAllowlist時 |

### 計算ロジック

- sysctl名の正規化: `utilsysctl.NormalizeName(sysctl)`
- カーネルバージョン比較: `kernelVersion.AtLeast(version.MustParseGeneric(sc.kernel))`

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

本機能はデータベースを直接操作しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | パターン不正 | カスタム許可パターンが無効 | NewAllowlist時にエラー返却（Kubelet起動失敗） |
| - | UnknownNamespace | 名前空間不明のsysctl | NewAllowlist時にエラー返却 |
| SysctlForbidden | Admission拒否 | 許可リストにないsysctl使用 | PodAdmitResult{Admit: false} |

### リトライ仕様

Admission拒否はリトライされない。Podの再投入時に同じチェックが適用される。

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

該当なし。

## パフォーマンス要件

- Admissionチェックはマップルックアップとプレフィックスマッチで高速（O(n)、nはプレフィックス数）
- 安全リスト生成はKubelet起動時に一度のみ実行

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

- 名前空間分離されていないsysctlの変更はノード全体に影響するため、厳格にブロックする
- hostNetwork/hostIPC使用時のsysctl制約は、名前空間共有によるセキュリティリスクを防止
- カスタム許可リストは管理者のみが--allowed-unsafe-sysctlsフラグで設定可能

## 備考

- SafeSysctlAllowlistはLinuxのみで機能する（他のOSではnilを返す）
- カーネルバージョンによって安全なsysctlの一覧が変わる（例: net.ipv4.tcp_keepalive_timeはカーネル4.15以降）

---

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

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

### 推奨読解順序

#### Step 1: 安全sysctlリストを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | safe_sysctls.go | `pkg/kubelet/sysctl/safe_sysctls.go` | sysctl構造体（28-33行目）: sysctl名と最小カーネルバージョン |
| 1-2 | safe_sysctls.go | `pkg/kubelet/sysctl/safe_sysctls.go` | safeSysctls変数（35-72行目）: 安全sysctlの一覧定義 |
| 1-3 | safe_sysctls.go | `pkg/kubelet/sysctl/safe_sysctls.go` | SafeSysctlAllowlist（79-85行目）: 公開エントリーポイント |
| 1-4 | safe_sysctls.go | `pkg/kubelet/sysctl/safe_sysctls.go` | getSafeSysctlAllowlist（87-108行目）: カーネルバージョンフィルタリング |

**読解のコツ**: `safeSysctls`スライスの各エントリの`kernel`フィールドが空の場合、全カーネルバージョンで安全。`kernel`が設定されている場合、そのバージョン以降でのみ安全（名前空間分離されている）。

**安全sysctl一覧**（コードから読み取り）:
- `kernel.shm_rmid_forced` - カーネルバージョン制約なし
- `net.ipv4.ip_local_port_range` - カーネルバージョン制約なし
- `net.ipv4.tcp_syncookies` - カーネルバージョン制約なし
- `net.ipv4.ping_group_range` - カーネルバージョン制約なし
- `net.ipv4.ip_unprivileged_port_start` - カーネルバージョン制約なし
- `net.ipv4.ip_local_reserved_ports` - IPLocalReservedPortsNamespacedKernelVersion以降
- `net.ipv4.tcp_keepalive_time` - TCPKeepAliveTimeNamespacedKernelVersion以降
- `net.ipv4.tcp_fin_timeout` - TCPFinTimeoutNamespacedKernelVersion以降
- `net.ipv4.tcp_keepalive_intvl` - TCPKeepAliveIntervalNamespacedKernelVersion以降
- `net.ipv4.tcp_keepalive_probes` - TCPKeepAliveProbesNamespacedKernelVersion以降
- `net.ipv4.tcp_rmem` - TCPReceiveMemoryNamespacedKernelVersion以降
- `net.ipv4.tcp_wmem` - TCPTransmitMemoryNamespacedKernelVersion以降

#### Step 2: 許可リストとAdmissionを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | allowlist.go | `pkg/kubelet/sysctl/allowlist.go` | patternAllowlist構造体（36-39行目）: sysctlsマップとprefixesマップ |
| 2-2 | allowlist.go | `pkg/kubelet/sysctl/allowlist.go` | NewAllowlist（44-69行目）: 許可リスト構築 |
| 2-3 | allowlist.go | `pkg/kubelet/sysctl/allowlist.go` | validateSysctl（78-102行目）: 個別sysctl検証 |
| 2-4 | allowlist.go | `pkg/kubelet/sysctl/allowlist.go` | Admit（106-127行目）: PodAdmissionハンドラ |

**主要処理フロー**:
- **50-67行目**: 各パターンについて、バリデーション→名前空間取得→sysctls/prefixesマップに登録
- **59-61行目**: UnknownNamespaceのsysctlはエラー
- **79行目**: sysctl名を正規化（スラッシュをドットに変換等）
- **81-88行目**: 完全一致でsysctlsマップを検索、名前空間制約チェック
- **90-99行目**: プレフィックスマッチでprefixesマップを検索
- **106-127行目**: SecurityContext.Sysctlsの全エントリを検証、1つでも失敗したらAdmit=false

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

```
Kubelet起動
    │
    ├─ SafeSysctlAllowlist()
    │      └─ getSafeSysctlAllowlist()
    │             └─ utilkernel.GetVersion()
    │
    └─ NewAllowlist(safeSysctls + customSysctls)
           ├─ policyvalidation.IsValidSysctlPattern()
           └─ utilsysctl.GetNamespace()

Lifecycle Manager (PodAdmitHandler chain)
    │
    └─ patternAllowlist.Admit()
           └─ validateSysctl() [各sysctl]
                  ├─ utilsysctl.NormalizeName()
                  ├─ sysctls map lookup (完全一致)
                  ├─ prefixes map scan (プレフィックスマッチ)
                  └─ IPC/NET Namespace + hostIPC/hostNet制約チェック
```

### データフロー図

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

カーネルバージョン ────▶ SafeSysctlAllowlist() ──▶ 安全sysctlリスト
カスタム許可パターン ──▶ NewAllowlist() ──────────▶ patternAllowlist
Pod SecurityContext ──▶ Admit() ──────────────────▶ PodAdmitResult
  └─ Sysctls              └─ validateSysctl()          └─ Admit/Reject + Reason
  └─ HostNetwork
  └─ HostIPC
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| allowlist.go | `pkg/kubelet/sysctl/allowlist.go` | ソース | sysctl許可リストとAdmission |
| safe_sysctls.go | `pkg/kubelet/sysctl/safe_sysctls.go` | ソース | 安全sysctlリストの生成 |
| allowlist_test.go | `pkg/kubelet/sysctl/allowlist_test.go` | テスト | 許可リストのテスト |
| safe_sysctls_test.go | `pkg/kubelet/sysctl/safe_sysctls_test.go` | テスト | 安全sysctlリストのテスト |
| sysctl.go | `staging/src/k8s.io/component-helpers/node/util/sysctl/sysctl.go` | ソース | sysctl名前空間判定ユーティリティ |
| kernel_version.go | `pkg/util/kernel/constants.go` | ソース | カーネルバージョン定数定義 |
