# ========================================================================== # claude-code — Claude Code リモート実行 Helm チャート # -------------------------------------------------------------------------- # 構成: # gateway ... 受付 nginx。ブラウザ ↔ セッションの単一入口。認証・WebSocket # プロキシ・アクティビティ計測を担う。 # manager ... 制御プレーン(Python 標準ライブラリのみ)。セッションの # 作成/一覧/破棄 API、Web UI、アイドル回収ループ。 # session ... セッションごとに作られる使い捨て Pod。Alpine ベースで # git clone → 編集 → 検証 → push を行い、claude を ttyd 経由で # ブラウザに提供する。アイドルで自動破棄。 # # セキュリティ上の注意(必読): # - この values.yaml に平文の API キー / SSH 秘密鍵 / トークンを書かない。 # Git にコミットしない。実値は CI の --set / --set-file か existingSecret で注入する。 # - セッション Pod は API サーバーへアクセスできない(SA トークン非マウント)。 # - セッション Pod の egress は Git ホストと api.anthropic.com のみに制限される # (networkPolicy.enabled: true のとき)。 # - 詳細は README.md「セキュリティモデル」を参照。 # ========================================================================== nameOverride: "" fullnameOverride: "" # -------------------------------------------------------------------------- # image: すべて Alpine ベース / linux/arm64 対応イメージ # -------------------------------------------------------------------------- image: # 受付 nginx(非 root 版) gateway: registry: docker.io repository: nginxinc/nginx-unprivileged tag: "1.29.1-alpine" pullPolicy: IfNotPresent # 制御プレーン(Python 標準ライブラリのみ・追加 pip 不要) manager: registry: docker.io repository: library/python tag: "3.13-alpine" pullPolicy: IfNotPresent # セッションの使い捨てコンテナ。 # 既定は CI(session-image.yaml)がビルドする事前ビルドイメージ # (git + openssh + ttyd + node + @anthropic-ai/claude-code 同梱、非 root 実行)。 # restricted PodSecurity / readOnlyRootFilesystem 下で確実に動くのはこの方式。 # # 事前ビルドを使わず素の node:alpine 等を指定することも可能だが、その場合 # ブート時に $HOME へ claude を npm インストールし、ttyd が同梱されていないと # 起動に失敗する(apk は非 root では不可)。フォールバック例: # registry: docker.io / repository: library/node / tag: "22-alpine" session: registry: git.cafepieters.com repository: helmchart/claude-code/session tag: "2.1.259" pullPolicy: IfNotPresent imagePullSecrets: [] # -------------------------------------------------------------------------- # gateway: 受付・ルーティング # -------------------------------------------------------------------------- gateway: replicaCount: 1 # gateway コンテナの待受ポート(Service / Ingress のバックエンド) port: 8080 resources: requests: cpu: 25m memory: 32Mi limits: cpu: 250m memory: 128Mi # -------------------------------------------------------------------------- # manager: 制御プレーン # -------------------------------------------------------------------------- manager: # debug | info | warning | error logLevel: info resources: requests: cpu: 50m memory: 64Mi limits: cpu: 500m memory: 256Mi # -------------------------------------------------------------------------- # sessionsNamespace: セッション Pod を隔離するネームスペース # -------------------------------------------------------------------------- sessionsNamespace: # 空 = リリース先ネームスペースを使う。セキュリティ上、専用ネームスペースを推奨。 name: "claude-code-sessions" # true ならこのチャートがネームスペースを作成し PodSecurity ラベルを付与する。 # 既存ネームスペースを使う場合は false にし、下記ラベルを手動で付与すること。 create: true # PodSecurity admission レベル(restricted 準拠のセッション Pod を強制) podSecurityLevel: restricted # セッション NS 全体の使用量上限(暴走・過剰生成のブラスト半径を限定) resourceQuota: enabled: true # 省略値は session.maxSessions と session.resources から算出される。 # 明示指定するとそのまま ResourceQuota.spec.hard になる。 hard: {} # requests.cpu: "4" # requests.memory: 8Gi # limits.cpu: "16" # limits.memory: 32Gi # セッション NS のコンテナ既定値 / 上限 limitRange: enabled: true max: cpu: "4" memory: 4Gi default: cpu: "1" memory: 1Gi defaultRequest: cpu: 100m memory: 256Mi # -------------------------------------------------------------------------- # auth: ブラウザからのアクセス認証 # -------------------------------------------------------------------------- auth: # token : Bearer トークン / Cookie / ?token= で検証(既定) # basic : HTTP Basic 認証(htpasswd) # forward : 外部認証プロキシ(oauth2-proxy 等)へ auth_request を委譲 # none : 認証なし(信頼済みネットワーク限定・非推奨) mode: token token: # 空なら install 時に自動生成される(helm get manifest で参照可能なため、 # 運用では existingSecret を使うのが望ましい)。 value: "" existingSecret: "" existingSecretKey: "token" basic: # `htpasswd -nbB user pass` の出力を1行以上。existingSecret 優先。 users: [] existingSecret: "" existingSecretKey: "htpasswd" forward: # nginx auth_request の転送先(例: http://oauth2-proxy.auth.svc.cluster.local:4180/oauth2/auth) url: "" # 未認証時のリダイレクト先(任意) signInUrl: "" # -------------------------------------------------------------------------- # anthropic: Claude Code の認証情報 # -------------------------------------------------------------------------- anthropic: # apiKey : ANTHROPIC_API_KEY を使う # oauth : CLAUDE_CODE_OAUTH_TOKEN を使う(`claude setup-token` で発行) authMode: apiKey apiKey: "" oauthToken: "" # 上記の代わりに既存 Secret を参照 existingSecret: "" existingSecretKeyApiKey: "ANTHROPIC_API_KEY" existingSecretKeyOauthToken: "CLAUDE_CODE_OAUTH_TOKEN" # 全セッションへ渡す追加環境変数(例: ANTHROPIC_BASE_URL / ANTHROPIC_MODEL) extraEnv: {} # -------------------------------------------------------------------------- # git: 接続先ホストと認証アイデンティティ # -------------------------------------------------------------------------- git: # チェックアウトを許可するホスト allow-list。manager はこれ以外のホストを拒否する。 allowedHosts: - github.com - gitlab.com - 192.168.9.65 - git.cafepieters.com # allow-list を無効化し任意 URL を許可する(非推奨) allowArbitraryRepos: false # コミット時の既定 author(セッション作成時に上書き可) defaultAuthorName: "Claude" defaultAuthorEmail: "claude@cafepieters.com" # 認証アイデンティティ。セッション作成時に名前で選択する。 # GitHub / Gitea / GitLab など SSH または HTTPS トークンで認証する任意のホストに対応。 identities: {} # gitea-ssh: # type: ssh # ssh | https-token # # --- ssh のとき --- # sshPrivateKey: "" # PEM 形式。existingSecret 優先 # knownHosts: "" # `ssh-keyscan ` の出力(必須/ホスト鍵TOFUを無効化) # # --- 既存 Secret を使う場合 --- # existingSecret: "" # existingSecretKeyPrivateKey: "id" # existingSecretKeyKnownHosts: "known_hosts" # github-https: # type: https-token # username: "x-access-token" # GitHub は任意文字列、Gitea はユーザー名 # token: "" # PAT。existingSecret 優先 # existingSecret: "" # existingSecretKeyToken: "token" # -------------------------------------------------------------------------- # session: 使い捨てセッションの挙動とライフサイクル # -------------------------------------------------------------------------- session: # ブート完了後に `claude` を自動起動する(false ならログインシェルで待受) autoStartClaude: true # リポジトリを clone する作業ディレクトリ workspaceDir: /workspace # ttyd の待受ポート(Pod 内からのみ到達可能) ttydPort: 7681 # ブート時に追加インストールする apk パッケージ(言語ランタイム等) extraApkPackages: [] # インストールする @anthropic-ai/claude-code のバージョン(空 = チャート appVersion) claudeCodeVersion: "" resources: requests: cpu: 100m memory: 256Mi limits: cpu: "2" memory: 2Gi ephemeral-storage: 4Gi # ---- lifecycle: 破棄条件 ---- # 無通信がこの秒数継続したセッションを破棄する(Pod 内ウォッチドッグ + manager 回収) idleTimeoutSeconds: 1800 # 生成からの最大寿命(Pod の activeDeadlineSeconds)。到達で強制終了。 maxLifetimeSeconds: 43200 reaper: # manager 内アイドル回収ループの実行間隔 intervalSeconds: 60 # 予備の孤児掃除 CronJob(manager 障害時の保険) cronjob: enabled: true schedule: "*/15 * * * *" # 同時に存在できるセッション数の上限(manager が enforce) maxSessions: 10 # ---- verify / push ---- # セッション内の `claude-verify` が実行するコマンド(例: "npm test" / "make check") verifyCommand: "" autoPush: # true でもデフォルトブランチや protectedBranches への push、--force は禁止。 enabled: false branchPrefix: "claude/" protectedBranches: - main - master - develop - release # セッション Pod への追加メタデータ / スケジューリング podLabels: {} podAnnotations: {} nodeSelector: {} tolerations: [] # セッション Pod の優先度クラス(任意) priorityClassName: "" # -------------------------------------------------------------------------- # networkPolicy: 通信制限(CNI が NetworkPolicy 対応であること) # -------------------------------------------------------------------------- networkPolicy: enabled: true # DNS 解決を許可する kube-dns の namespace セレクタ dnsNamespaceSelector: kubernetes.io/metadata.name: kube-system # api.anthropic.com / GitHub は IP 固定できないため、既定でセッションの # 443/tcp(HTTPS git・Claude API)と 22/tcp(SSH git)の外向きを許可する。 # 完全に閉じる場合は egress プロキシを用意し false にする。 allowInternetHttps: true allowSshGit: true # allowInternetHttps 時に egress から除外する CIDR(SSRF 対策)。 # クラウドのメタデータ IP は既定で遮断。自クラスターの Pod/Service CIDR を # 追加すると、セッションから内部サービスへの到達を防げる。 blockedEgressCIDRs: - 169.254.169.254/32 # 追加で許可する egress(社内ミラー / プロキシ用) sessionEgressExtra: [] # - cidr: 10.0.0.0/8 # ports: # - protocol: TCP # port: 443 # -------------------------------------------------------------------------- # ingress / service # -------------------------------------------------------------------------- ingress: enabled: false className: "" annotations: {} # nginx.ingress.kubernetes.io/proxy-read-timeout: "3600" # nginx.ingress.kubernetes.io/proxy-send-timeout: "3600" hosts: - host: claude-code.example.com paths: - path: / pathType: Prefix tls: [] # - secretName: claude-code-tls # hosts: # - claude-code.example.com service: type: ClusterIP port: 80 # -------------------------------------------------------------------------- # 制御プレーンの Pod / コンテナセキュリティ # -------------------------------------------------------------------------- podSecurityContext: runAsNonRoot: true runAsUser: 65532 runAsGroup: 65532 fsGroup: 65532 seccompProfile: type: RuntimeDefault containerSecurityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: - ALL # 全リソースへ付与する追加ラベル / アノテーション commonLabels: {} commonAnnotations: {} podDisruptionBudget: enabled: false minAvailable: 1