# 帳票設計書 73-監査ログ（Legacy形式）

## 概要

本ドキュメントは、Kubernetes APIサーバの監査イベントを1行テキスト形式（Legacy形式）でログファイルに出力する帳票の設計書である。audit logバックエンドの `FormatLegacy` モードとして提供される。

### 本帳票の処理概要

本帳票は、Kubernetes APIサーバに対するすべてのAPIリクエストの監査イベントを、人間が読みやすい1行テキスト形式でログファイルに記録する機能を提供する。

**業務上の目的・背景**：Kubernetesクラスタのセキュリティ監査において、誰が・いつ・何に対して・どのような操作を行ったかを記録することは、コンプライアンス要件の充足やセキュリティインシデントの調査に不可欠である。Legacy形式は、各監査イベントを1行のテキストとして出力することで、grepやawk等の標準的なテキスト処理ツールで容易に検索・フィルタリングできることを目的としている。

**帳票の利用シーン**：セキュリティ管理者がAPIリクエストの履歴を確認する際に利用される。例えば、不正アクセスの調査、権限昇格の試行の検知、リソース変更操作の追跡、コンプライアンス監査での証跡確認などに使用される。

**主要な出力内容**：
1. タイムスタンプ（RFC3339Nano形式）
2. 監査ID（AuditID）
3. リクエストステージ（Stage）
4. ソースIP
5. HTTPメソッド/Verb
6. ユーザ名・グループ
7. 偽装ユーザ情報（Impersonation）
8. User-Agent
9. 対象Namespace
10. リクエストURI
11. レスポンスステータスコード

**帳票の出力タイミング**：APIサーバがリクエストを処理する各ステージ（RequestReceived, ResponseStarted, ResponseComplete, Panic）で、監査ポリシーに基づいてイベントが生成される都度出力される。

**帳票の利用者**：セキュリティ管理者、クラスタ管理者、監査担当者

## 帳票種別

監査ログ（テキスト形式）

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | APIサーバ設定 | kube-apiserver --audit-log-path --audit-log-format=legacy | APIサーバ起動時設定 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | テキスト（1イベント1行） |
| 用紙サイズ | N/A（ログファイル） |
| 向き | N/A |
| ファイル名 | --audit-log-pathで指定されたファイルパス |
| 出力方法 | io.Writerへのストリーム書き込み |
| 文字コード | UTF-8 |

### ログ出力仕様

| 項目 | 内容 |
|-----|------|
| 1行の形式 | `{timestamp} AUDIT: id="{auditID}" stage="{stage}" ip="{ip}" method="{verb}" user="{user}" groups="{groups}" as="{asuser}" asgroups="{asgroups}" user-agent="{ua}" namespace="{ns}" uri="{uri}" response="{code}"` |
| 行末 | 改行文字（\n） |
| フォーマット名 | "legacy"（FormatLegacy定数） |

## 帳票レイアウト

### レイアウト概要

1イベント1行のフラットテキスト形式で出力する。ヘッダー部やフッター部は存在しない。

```
2024-01-15T10:30:00.000000000Z AUDIT: id="abc-123" stage="ResponseComplete" ip="192.168.1.1" method="get" user="admin" groups="\"system:masters\"" as="<self>" asgroups="<lookup>" user-agent="kubectl/v1.29.0" namespace="default" uri="/api/v1/namespaces/default/pods" response="200"
2024-01-15T10:30:01.000000000Z AUDIT: id="def-456" stage="ResponseComplete" ip="10.0.0.1" method="create" user="developer" groups="\"developers\"" as="<self>" asgroups="<lookup>" user-agent="kubectl/v1.29.0" namespace="kube-system" uri="/api/v1/namespaces/kube-system/configmaps" response="201"
```

### ヘッダー部

ヘッダー部は存在しない。

### 明細部

各行は以下のフィールドで構成される（EventString関数による生成）。

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | timestamp | リクエスト受信時刻 | Event.RequestReceivedTimestamp | RFC3339Nano形式 |
| 2 | AUDIT固定文字列 | ログ種別識別子 | 固定値 | "AUDIT:" |
| 3 | id | 監査ID | Event.AuditID | `id="{値}"` |
| 4 | stage | リクエストステージ | Event.Stage | `stage="{値}"` |
| 5 | ip | ソースIP | Event.SourceIPs[0] | `ip="{値}"` (なければ`<unknown>`) |
| 6 | method | HTTPメソッド/Verb | Event.Verb | `method="{値}"` |
| 7 | user | ユーザ名 | Event.User.Username | `user="{値}"` (なければ`<none>`) |
| 8 | groups | ユーザグループ | Event.User.Groups | `groups="{値}"` (なければ`<none>`) |
| 9 | as | 偽装ユーザ | Event.ImpersonatedUser.Username | `as="{値}"` (なければ`<self>`) |
| 10 | asgroups | 偽装グループ | Event.ImpersonatedUser.Groups | `asgroups="{値}"` (なければ`<lookup>`) |
| 11 | user-agent | User-Agent | Event.UserAgent | `user-agent="{値}"` |
| 12 | namespace | 対象Namespace | Event.ObjectRef.Namespace | `namespace="{値}"` (なければ`<none>`) |
| 13 | uri | リクエストURI | Event.RequestURI | `uri="{値}"` |
| 14 | response | レスポンスコード | Event.ResponseStatus.Code | `response="{値}"` (なければ`<deferred>`) |

### フッター部

フッター部は存在しない。

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| 監査ポリシー | audit.k8s.io/v1 Policy で定義されたルール | Yes |
| 監査レベル | None/Metadata/Request/RequestResponse | Yes |
| OmitStages | 除外するステージ | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | イベント発生順（時系列） | 昇順 |

### 改ページ条件

改ページは発生しない（1行1イベントのストリーム出力）。

## データベース参照仕様

### 参照テーブル一覧

本帳票はデータベースを参照せず、APIサーバ内部の監査イベントオブジェクトを直接処理する。

| データ構造 | 用途 | 備考 |
|-----------|------|------|
| auditinternal.Event | 監査イベント本体 | apiserver/pkg/apis/audit/types.go で定義 |

### テーブル別参照項目詳細

#### auditinternal.Event

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| RequestReceivedTimestamp | timestamp | - | MicroTime型、RFC3339Nano形式で出力 |
| AuditID | id | - | types.UID型 |
| Stage | stage | - | RequestReceived/ResponseStarted/ResponseComplete/Panic |
| SourceIPs | ip | [0]番目を使用 | 空の場合は`<unknown>` |
| Verb | method | - | kubernetes verb |
| User.Username | user | - | 空の場合は`<none>` |
| User.Groups | groups | - | 空の場合は`<none>` |
| ImpersonatedUser.Username | as | nilの場合は`<self>` | - |
| ImpersonatedUser.Groups | asgroups | nilの場合は`<lookup>` | - |
| UserAgent | user-agent | - | - |
| ObjectRef.Namespace | namespace | ObjectRefがnilまたはNamespace空の場合は`<none>` | - |
| RequestURI | uri | - | - |
| ResponseStatus.Code | response | nilの場合は`<deferred>` | int32型、strconv.Itoaで文字列変換 |

## 計算仕様

### 計算項目一覧

本帳票には計算項目は存在しない。すべてのフィールドは監査イベントオブジェクトから直接取得される。

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[APIリクエスト受信] --> B[監査ポリシー評価]
    B --> C{監査レベル判定}
    C -->|None| D[出力なし]
    C -->|Metadata以上| E[Eventオブジェクト生成]
    E --> F[ProcessEvents呼び出し]
    F --> G[logEvent: フォーマット判定]
    G --> H[EventString関数でLegacy形式文字列生成]
    H --> I[io.Writerへ書き込み]
    I --> J[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| 書き込みエラー | io.Writerへの書き込み失敗 | HandlePluginError経由で記録 | ログファイルのディスク容量・権限確認 |
| 不明フォーマット | format値がlegacy/json以外 | "log format %q is not in list of known formats" | APIサーバ設定確認 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | APIリクエスト数に比例（毎秒数十〜数千イベント） |
| 目標出力時間 | 同期書き込み（APIリクエスト処理に同期） |
| 同時出力数上限 | APIサーバの並行リクエスト数に依存 |

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

- 監査ログにはユーザ名、IPアドレス、リクエストURIが含まれるため、ログファイルへのアクセス制御が必要
- 監査レベルに応じてRequest/ResponseBodyも記録される可能性があり、機密情報が含まれる場合がある
- ログファイルのローテーションと保存期間の管理が必要
- Legacy形式ではRequestObject/ResponseObjectは出力されない（EventString関数にはこれらのフィールドが含まれない）

## 備考

- Legacy形式はEventString関数（format.go）を使用して1行テキストに変換する
- JSON形式（No.74）と同じbackend構造体を共有し、format フィールドで切り替える
- backend構造体のRun()メソッドは何もしない（同期書き込みのためバッチ処理不要）
- Shutdown()メソッドも何もしない
- ProcessEventsは複数イベントを受け取り、各イベントをlogEventで個別処理する

---

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

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

### 推奨読解順序

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

まず、監査イベントのデータ構造を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.go | `staging/src/k8s.io/apiserver/pkg/apis/audit/types.go` | Event構造体（行79-152）の全フィールドを把握。特にLevel, Stage, User, ImpersonatedUser, ObjectRef, ResponseStatusの構造に注目 |
| 1-2 | types.go | `staging/src/k8s.io/apiserver/pkg/apis/audit/types.go` | Level定数（行44-56）とStage定数（行62-74）で監査レベルとステージの種類を確認 |

**読解のコツ**: Event構造体はmetav1.TypeMetaを埋め込んでいるが、Legacy形式ではTypeMetaのフィールドは使用しない。RequestObject/ResponseObjectはLegacy形式では出力対象外。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | backend.go | `staging/src/k8s.io/apiserver/plugin/pkg/audit/log/backend.go` | backend構造体（行46-50）とNewBackend関数（行54-60）でバックエンドの初期化を理解 |
| 2-2 | backend.go | `staging/src/k8s.io/apiserver/plugin/pkg/audit/log/backend.go` | FormatLegacy/FormatJson定数（行31-34）とAllowedFormats（行41-44）でフォーマット定義を確認 |

**主要処理フロー**:
1. **行54-60**: NewBackend関数でio.Writer, format, encoderを設定
2. **行62-68**: ProcessEvents関数で複数イベントを受け取り、各イベントをlogEventで処理
3. **行70-92**: logEvent関数でフォーマットに応じた文字列生成と書き込み

#### Step 3: Legacy形式の文字列生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | format.go | `staging/src/k8s.io/apiserver/pkg/audit/format.go` | EventString関数（行30-65）で1行テキスト形式の生成ロジックを理解。各フィールドのデフォルト値（`<none>`, `<self>`, `<unknown>`, `<deferred>`）に注目 |
| 3-2 | format.go | `staging/src/k8s.io/apiserver/pkg/audit/format.go` | auditStringSlice関数（行67-73）でグループ情報のフォーマット処理を確認 |

**主要処理フロー**:
- **行31-38**: ユーザ名/グループのデフォルト値設定（`<none>`）
- **行40-46**: 偽装ユーザの処理（nil時は`<self>`/`<lookup>`）
- **行48-51**: Namespaceの取得（ObjectRefがnil時は`<none>`）
- **行53-56**: レスポンスコードの取得（nil時は`<deferred>`）
- **行58-60**: ソースIPの取得（空時は`<unknown>`）
- **行63-64**: fmt.Sprintfで最終フォーマット文字列を生成

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

```
kube-apiserver (監査ハンドラ)
    |
    +-- audit.Backend.ProcessEvents (backend.go:62)
            |
            +-- logEvent (backend.go:70)
                    |
                    +-- [FormatLegacy] audit.EventString (format.go:30)
                    |       +-- auditStringSlice (format.go:67)
                    |       +-- fmt.Sprintf (行63-64)
                    |
                    +-- fmt.Fprint(b.out, line) (backend.go:87)
```

### データフロー図

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

APIリクエスト              監査ポリシー評価
(audit.Event) ---------> ProcessEvents() ----+
                                              |
                          logEvent()           |
                          format="legacy"      +--> EventString() --> io.Writer
                                                    (1行テキスト)      (ログファイル)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| backend.go | `staging/src/k8s.io/apiserver/plugin/pkg/audit/log/backend.go` | ソース | 監査ログバックエンド本体 |
| format.go | `staging/src/k8s.io/apiserver/pkg/audit/format.go` | ソース | Legacy形式文字列生成（EventString関数） |
| types.go | `staging/src/k8s.io/apiserver/pkg/apis/audit/types.go` | ソース | 監査イベント型定義（Event, Policy, Stage, Level） |
| union.go | `staging/src/k8s.io/apiserver/pkg/audit/union.go` | ソース | 複数バックエンドの統合処理 |
