feat: credentials 認証モードとトークン自動リフレッシュ CronJob を追加 (v2.1.263-b)
Helm Chart Release / release-chart (push) Successful in 9s
Build Session Image / build-push (push) Successful in 2m8s

トークンが定期的に失効・ローテーションしても再デプロイ不要にする。

- anthropic.authMode: credentials(新既定)
  ~/.claude/.credentials.json 全体(refreshToken 込み)を Secret に格納。
  セッション Pod にはファイルとしてマウントし $HOME/.claude へコピー(書き込み可)、
  セッション内 claude が refreshToken で自己更新
- anthropic.refresher CronJob(credentials 時・既定有効, files/token-refresher.py)
  Secret 内 refreshToken で OAuth トークンを更新し Secret を書き戻す。
  専用 SA + resourceNames 限定 Role で該当 Secret の get/patch のみ。
  tokenUrl/clientId は Claude Code CLI の非公式値(values 上書き可)
- manager.py build_pod: credentials は envFrom を使わずファイルマウント +
  SEED_CREDENTIALS_FILE。apiKey/oauth は従来どおり envFrom
- Secret に helm.sh/resource-policy: keep(credentials 時)で refresher の書込を保持
- fix: values.schema.json の $schema 行を削除(一部の Helm で
  "no schema with key or ref https://json-schema.org/draft-07/schema#" エラー)
- helm lint / template(credentials/apiKey/oauth)検証済み
This commit is contained in:
2026-09-08 15:18:21 +09:00
parent cd7092be17
commit 528a48b667
15 changed files with 503 additions and 46 deletions
+62 -28
View File
@@ -119,41 +119,63 @@ manager / gateway / session-entrypoint の実体は `files/` にあり、`.Files
**サブスクリプション認証(Pro / Max プラン)** で動かせます。セッション内の `claude` の
挙動・機能はローカル実行と同一です(同じ CLI・同じログイン方式)。
1. 手元の PC(Claude にログイン済み)で長期トークンを発行:
`anthropic.authMode` は 3 つ:
```bash
claude setup-token
```
| モード | 注入するもの | トークン更新 | 課金 |
|---|---|---|---|
| **`credentials`(既定・推奨)** | `~/.claude/.credentials.json` 全体(`refreshToken` 込み) | セッション内 `claude` が自己更新 **+** クラスタ内 refresher CronJob が Secret を自動更新 | サブスクリプション枠(API 課金なし) |
| `oauth` | `CLAUDE_CODE_OAUTH_TOKEN`(`claude setup-token` の単発トークン) | 自動更新なし(`refreshToken` を含まない)。失効したら手動再投入 | サブスクリプション枠 |
| `apiKey` | `ANTHROPIC_API_KEY`(`sk-ant-...`) | — | API 従量課金 |
ブラウザで承認すると `CLAUDE_CODE_OAUTH_TOKEN` として使える長期トークンが表示されます。
### `credentials` モードの使い方(推奨)
2. それをチャートに渡す(`authMode: oauth`):
1. **claude にログイン済みの手元 PC** の認証情報ファイルをそのまま渡します
(このファイルには `accessToken` と、それを更新するための `refreshToken` が入っています):
```bash
# 場所: Linux/macOS = ~/.claude/.credentials.json
# Windows = %USERPROFILE%\.claude\.credentials.json
# (macOS でキーチェーン保存の場合は Keychain の "Claude Code" 項目を書き出す)
helm upgrade --install claude-code cafepieters/claude-code -n claude-code --create-namespace \
-f examples/loadbalancer-oauth.values.yaml \
--set anthropic.oauthToken="<発行されたトークン>"
--set-file anthropic.credentialsJson="$HOME/.claude/.credentials.json"
```
Secret にしておく場合:
2. これだけで **トークンが定期的に変わっても再デプロイは不要** です。仕組み:
- セッション Pod は生成のたびに Secret を読むため、常に最新の認証情報で起動します。
- **セッション内の `claude`** は、`accessToken` が失効していれば `refreshToken` で
自動更新します(そのセッションの間だけ有効。`$HOME/.claude/.credentials.json` に書き戻す)。
- **refresher CronJob**(`anthropic.refresher`、既定 30 分ごと)が、Secret 内の
`refreshToken` を使ってクラスタ内で `accessToken` を更新し、**Secret 自体を書き戻します**。
これにより手元 PC がオフラインでも、新規セッションは常に有効なトークンで起動できます。
3. 既存 Secret を使う場合:
```bash
kubectl -n claude-code-sessions create secret generic claude-oauth \
--from-literal=CLAUDE_CODE_OAUTH_TOKEN="<トークン>"
# values: anthropic.existingSecret=claude-oauth
kubectl -n claude-code-sessions create secret generic claude-creds \
--from-file=.credentials.json="$HOME/.claude/.credentials.json"
# values: anthropic.existingSecret=claude-creds
# (refresher に patch させるため RBAC はこの Secret 名に限定して付与される)
```
| 方式 | values | 認証情報 | 課金 |
|---|---|---|---|
| **サブスクリプション(推奨)** | `anthropic.authMode: oauth` | `anthropic.oauthToken`(`claude setup-token`) | Claude プランの利用枠を消費(API 課金なし) |
| API キー | `anthropic.authMode: apiKey` | `anthropic.apiKey`(`sk-ant-...`) | API 従量課金 |
### 注意 / 制約
- トークンは **セッション NS の Secret** に保存され、セッション Pod へ環境変数
`CLAUDE_CODE_OAUTH_TOKEN` として注入されます(`values.yaml` に平文で書かない)。
- 利用枠はローカルの Claude Code と共有です。複数セッションを同時に走らせると
プランのレート上限に早く達する点に注意してください。
- トークンには有効期限があります。失効したら `claude setup-token` で再発行し
`helm upgrade --set anthropic.oauthToken=...`(または Secret 更新 + Pod 再起動)します。
- 利用枠はローカルの Claude Code と共有です。同時セッションを増やすとプランの
レート上限に早く達します。
- `session.maxLifetimeSeconds`(既定 12h)が `accessToken` の寿命より長いと、長時間
セッションが自分でトークンを更新し、`refreshToken` のローテーションで refresher 側の
値が一時的に古くなることがあります。refresher は短い周期(既定 30 分)で追従します。
- **refresher は Claude Code CLI の OAuth クライアント値(`anthropic.refresher.tokenUrl` /
`clientId`)に依存します。これらは非公式で、仕様変更により動かなくなる可能性があります。**
その場合でもセッション内 `claude` の自己更新は独立して機能します(新規セッションの
起動時トークンが古い場合のみ影響)。不要なら `anthropic.refresher.enabled: false`。
- refresher の権限は **セッション NS の認証情報 Secret 1 個への `get` / `patch` のみ**
(`resourceNames` で限定した Role)。
- `refreshToken` 自体が失効・失効させられた場合は、手元 PC で `claude` に再ログインして
`--set-file anthropic.credentialsJson=...` で再投入します。
- Secret の中身は refresher が書き換えます。`helm upgrade` で `--set-file` を付けない限り
Helm は Secret の値を上書きしません(`helm.sh/resource-policy: keep` + 3-way merge)。
## 管理画面へのアクセス(LoadBalancer / Ingress)
@@ -226,7 +248,8 @@ ingress:
- LoadBalancer 実装(kube-vip / MetalLB / Cilium LB-IPAM など) … 既定
- Ingress コントローラー … `ingress.enabled: true` の場合
- どちらも無い場合は `service.type: ClusterIP` + `kubectl port-forward` で利用可
- Claude の認証情報 … `claude setup-token` の OAuth トークン(推奨)または `ANTHROPIC_API_KEY`
- Claude の認証情報 … `~/.claude/.credentials.json`(既定 `credentials` モード・推奨)
または `claude setup-token` の OAuth トークン、`ANTHROPIC_API_KEY`
### Helm リポジトリから
@@ -242,16 +265,17 @@ helm upgrade --install claude-code cafepieters/claude-code \
### ローカル LB の IP + サブスクリプション認証(API 不要・推奨構成)
```bash
claude setup-token # 手元の PC で長期 OAuth トークンを発行
# 手元の PC は claude にログイン済みであること(~/.claude/.credentials.json が存在)
helm upgrade --install claude-code cafepieters/claude-code \
-n claude-code --create-namespace \
-f examples/loadbalancer-oauth.values.yaml \
--set anthropic.oauthToken="<発行されたトークン>" \
--set-file anthropic.credentialsJson="$HOME/.claude/.credentials.json" \
--set-file git.identities.gitea-ssh.sshPrivateKey=P:/Claude/.ssh/id_claude \
--set-file git.identities.gitea-ssh.knownHosts=./known_hosts.gitea
```
以降トークンが変わっても再デプロイは不要です(refresher CronJob が Secret を追従更新)。
`examples/loadbalancer-oauth.values.yaml` は Ingress 無効・`service.type: LoadBalancer` +
kube-vip の VIP 指定 + `loadBalancerSourceRanges` によるローカルセグメント限定の構成です。
@@ -352,14 +376,23 @@ ssh-keyscan 192.168.9.65 > known_hosts.gitea
### anthropic — Claude Code 認証情報
詳細は [Claude 認証(API 課金なし / サブスクリプション)](#claude-認証api-課金なし--サブスクリプション) を参照。
| キー | 既定 | 説明 |
|---|---|---|
| `anthropic.authMode` | `apiKey` | `apiKey`(`ANTHROPIC_API_KEY`)/ `oauth`(`CLAUDE_CODE_OAUTH_TOKEN`) |
| `anthropic.authMode` | `credentials` | `credentials`(`~/.claude/.credentials.json`・推奨)/ `oauth`(`CLAUDE_CODE_OAUTH_TOKEN`)/ `apiKey`(`ANTHROPIC_API_KEY`) |
| `anthropic.credentialsJson` | `""` | `--set-file anthropic.credentialsJson=$HOME/.claude/.credentials.json` で注入 |
| `anthropic.apiKey` / `anthropic.oauthToken` | `""` | `--set` / `--set-file` で注入 |
| `anthropic.existingSecret` | `""` | 既存 Secret を使う(キー名は `existingSecretKeyApiKey` / `existingSecretKeyOauthToken`) |
| `anthropic.existingSecret` | `""` | 既存 Secret を使う(キー名は `existingSecretKeyCredentials`(既定 `.credentials.json`)/ `...ApiKey` / `...OauthToken`) |
| `anthropic.refresher.enabled` | `true` | `credentials` モードで、Secret 内 `refreshToken` を使いトークンを定期更新する CronJob を作成 |
| `anthropic.refresher.schedule` | `*/30 * * * *` | refresher CronJob のスケジュール |
| `anthropic.refresher.refreshIfExpiresInSeconds` | `3600` | `accessToken` の残り寿命がこの秒数未満なら更新 |
| `anthropic.refresher.tokenUrl` / `clientId` | Claude Code CLI の公開値 | OAuth トークンエンドポイントとクライアント ID(**非公式・仕様変更で要更新**) |
| `anthropic.extraEnv` | `{}` | 全セッションへ渡す追加 env(例 `ANTHROPIC_BASE_URL`、Bedrock/Vertex 切替など) |
Secret は **セッション NS** に作成され、セッション Pod へ `envFrom` で注入されます。
Secret は **セッション NS** に作成されます。`credentials` モードはファイルとしてマウントし
セッション起動時に `$HOME/.claude/.credentials.json` へコピー(書き込み可能)、
`apiKey` / `oauth` モードは `envFrom` で環境変数として注入します。
### git — 接続先と認証アイデンティティ
@@ -492,6 +525,7 @@ docker buildx build --platform linux/amd64,linux/arm64 \
| バージョン | Claude Code | 変更内容 |
|---|---|---|
| 2.1.263-b | 2.1.263 | `anthropic.authMode: credentials`(既定)を追加。`~/.claude/.credentials.json` 全体を注入し、セッション内 `claude` の自己更新に加え、クラスタ内 refresher CronJob(`refreshToken` で Secret を定期更新)でトークン失効に自動追従。→ トークンが変わっても再デプロイ不要。refresher の RBAC は認証情報 Secret 1 個の get/patch に限定 |
| 2.1.263-a | 2.1.263 | Service を `LoadBalancer` 対応(kube-vip 等でローカル LB の IP から管理画面へアクセス、`loadBalancerSourceRanges` で接続元制限、既定を `LoadBalancer` に変更)。Ingress は従来どおり併用可。API を使わないサブスクリプション認証(`claude setup-token` → `authMode: oauth`)の手順を README に追記 |
| 2.1.263 | 2.1.263 | 自動更新 |
| 2.1.259 | 2.1.259 | 初版。gateway + manager + 使い捨て session Pod + reaper、GitHub/Gitea 対応、アイドル自動破棄、NetworkPolicy / RBAC 最小化 / restricted PodSecurity |