EC-CUBE / EC-CUBE/ec-cube

共通の鍵保管ディレクトリ `app/keystore/` の導入 (各種暗号鍵・シークレットの標準置き場)

Open
#6,797 3 comments 0 reactions 3 assignees Claimed by @dotani1111 View on GitHub
document
Dominant language
PHP
Stars
788
Forks
719
Avg merge
4d 4h
Merged PRs (30d)
39

Description

## サマリー

EC-CUBE 本体に、**各種暗号鍵・シークレット素材のファイル保管を標準化する共通ディレクトリ `app/keystore/`** を新設することを提案します。

Agentic Commerce 対応 (#6777 / #6776 / #6574 / #6794) で UCP メッセージ署名用の **EC P-256 秘密鍵** が必要になるほか、読み取り専用 MCP サーバ (#6796) など今後の本体機能でも鍵・シークレット素材を保持する場面が想定されます。現状、core 機能が鍵を置く標準的な場所が無く、放置すると機能ごとにバラバラの置き場・保護方法が乱立する懸念があります。本 issue で **置き場と保護のルールを一本化**します。

| 項目 | 値 |
|------|-----|
| 対象バージョン | **EC-CUBE 4.4** (Symfony 7.4 / PHP 8.2+) |
| 種別 | 横断基盤 (cross-cutting) |
| 関連 | #6777 (共通基盤) / #6776 (ACP) / #6574 (UCP) / #6794 (Product Feed) / #6796 (MCP サーバ) |

---

## 背景・課題

- **鍵を持つ本体機能が増えつつある**:
- Agentic Commerce: UCP の RFC 9421 HTTP Message Signatures 用 **EC P-256 秘密鍵**、ACP Webhook 用 **HMAC 共有シークレット** (対称鍵) など。
- MCP サーバ (#6796): PAT (個人アクセストークン) を中核とする認証。将来的に署名・暗号鍵素材が生じうる。
- **既存の置き場はプラグイン専用**: eccube-api4 は OAuth2 の RSA 鍵を `app/PluginData/Api42/oauth/{private,public}.key` に置くが、`app/PluginData/` は**プラグインのデータ領域**であり、本体 (core) 機能が間借りするのは規約上不適切。
- **`dtb_baseinfo` への秘密鍵格納は避けたい**: DB ダンプ・バックアップ・レプリカに秘密が伝播するため、秘密鍵は DB の外に置く方が衛生的。
- **`var/` は揮発領域**: `cache:clear` 等で消えうるため、永続秘密鍵の置き場には不適。

→ **本体機能が共通で使える、保護方法が確立した鍵保管ディレクトリ**を 1 つ用意する。

---

## 提案

### ディレクトリ構成

```
app/keystore/ # 新設。core の暗号鍵・シークレット保管庫
.gitkeep
.htaccess # deny from all (多重防御)
/ # 機能単位でサブディレクトリ
.key
```

例:

```
app/keystore/agent-commerce/ucp_signing.key # UCP EC P-256 秘密鍵 (#6777/#6574)
app/keystore/agent-commerce/acp_webhook.secret # ACP Webhook HMAC 共有シークレット (#6776) ※将来
app/keystore/mcp/... # MCP サーバ用 (#6796) ※必要に応じて
```

- 命名は生成・永続データ系の `app/proxy` に倣い**小文字 `keystore`**。
- 機能ごとに `app/keystore//` でサブディレクトリを切り、鍵種が増えても衝突しない。

### 保護 (重要: `app/` は web ルート内)

EC-CUBE は `composer.json` の `"public-dir": "."` により**プロジェクトルート自体が docroot** で、web ルート外にファイルを置けないレンサバ前提の設計です。そのため `app/keystore/` も web ルート内に置かれ、**`.htaccess` / web サーバ設定による拒否**で保護します (eccube-api4 の鍵保管と同じ確立パターン)。

多重防御:

1. **`app/.htaccess`** の `deny from all` が `app/` 配下に再帰適用される (Apache・既存)。
2. **`nginx.conf.sample`** の `location ~^/(var|test|vendor|app|src|bin) { deny all; }` が `/app` を拒否 (既存)。
3. **`app/keystore/.htaccess`** に `deny from all` を明示配置する (本 issue で追加。各トップ階層が個別 `.htaccess` を持つ既存慣習に倣う)。
4. **ルート `.htaccess` の拡張子ブロックリストに `key` を追加** (`\.(ini|lock|…|key)$`)。`AllowOverride None` でサブディレクトリ `.htaccess` が無視される環境でも `.key` が直接配信されないようにする核心ガード。
5. **`.gitignore`** に追加し、鍵を VCS にコミットしない:
```
/app/keystore/*
!/app/keystore/.gitkeep
```
6. ファイルパーミッションは生成時に `600`。

### 鍵の解決順 (eccube-api4 パリティ)

クラウドの Secrets Manager / Key Vault 連携を可能にするため、**環境変数によるパス上書き → 既定ローカルファイル**の 2 段とする (eccube-api4 が OAuth2 鍵で採用している方式に合わせる):

```
1. 環境変数 (パス指定) ← AWS Secrets Manager / Azure Key Vault 等に対応。本番・Enterprise 推奨
2. 既定ファイル ← app/keystore//。env 不可環境 (共有レンサバ・ec-cube.co) のフォールバック。
初回利用 (機能有効化) 時に自動生成。
```

- **公開鍵は実行時に秘密鍵から導出**して公開面 (例: UCP discovery の `signing_keys[]`) に出力し、公開鍵ファイルを別途持たない (持つ場合も同ディレクトリ)。
- 各機能は鍵解決を共通の Provider 抽象 (例: `KeyProvider`) 経由にし、`app/Customize` での差し替え (Secrets Manager 実装の注入等) を可能にする。

---

## 対象 / 非対象

**対象 (ファイル保管が妥当なもの)**:
- 非対称秘密鍵 (UCP EC P-256 署名鍵 等)
- 対称シークレット (ACP Webhook HMAC 等) でファイル保持が必要なもの

**非対象 / 別管理**:
- env / Secrets Manager だけで完結できるシークレットは無理にファイル化しない (env 経路を推奨)。
- 公開しても問題ない設定値 (URL・ID 等) は従来どおり `dtb_baseinfo` 等の設定領域へ。
- **秘密鍵を `dtb_baseinfo` に格納しない** (本 issue の方針)。

---

## セキュリティ留意点

- `app/keystore/` は **web ルート内**であるため、`.htaccess` を honor しない構成 (`AllowOverride None`、自前 nginx で `/app` deny を入れ忘れ) では漏洩しうる。これは EC-CUBE 既存の構造的条件 (eccube-api4 鍵・`.env` 等も同条件) であり本 issue で新規に増やすリスクではないが、**漏洩耐性は env-var → Secrets Manager / Key Vault 経路が上位**であることをドキュメントで明示し推奨する。
- PCI / 個人情報を鍵ファイルに含めない (鍵素材のみ)。

---

## 受入基準 (Acceptance Criteria)

- [ ] `app/keystore/` を新設 (`.gitkeep` + `deny from all` の `.htaccess`)。
- [ ] `.gitignore` に `app/keystore/*` (除外 `.gitkeep`) を追加。
- [ ] ルート `.htaccess` の拡張子ブロックリストに `key` を追加し、既存で `.key` 配信に依存する箇所が無いことを確認。
- [ ] 鍵解決の共通 Provider 抽象 (env パス上書き → 既定ファイル、Customize 差し替え可) を用意。
- [ ] 上記を利用する最初の具象として #6777 の UCP EC P-256 署名鍵を `app/keystore/agent-commerce/` に配置 (本 issue では枠組みのみ、実鍵生成は #6777)。
- [ ] ドキュメント: 設置形態別 (Apache/Nginx) の保護設定、Secrets Manager 連携手順、共有レンサバ時の注意。

---

## 補足 / 未確定

- eccube-api4 が OAuth2 鍵を「プラグイン有効化時に自動生成」しているかは要確認。同じ自動生成作法を踏襲できるなら、共有レンサバ (CLI 不可) 環境でも env 不要で成立する。
- ディレクトリ casing は小文字 `keystore` を提案 (既存 `proxy` に整合)。PascalCase 規約を優先する場合は `KeyStore` も可。

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.