---
title: "シークレット"
description: "Beeuniがプロジェクトの認証情報を保存する方法と、エージェントコードが各値を読み取れるかどうかを制御する方法。"
---

シークレットはプロジェクト単位の認証情報です — API キー、トークン、または接続文字列など、セッションに必要ですが、リポジトリに保存してはならないものです。Beeuni はシークレットをアカウントではなくプロジェクトに保存し、プロジェクトごとに導出したキーを使って、すべての値を AES-256-GCM で暗号化します。

<a id="identifier-and-name"></a>

## 識別子と名前

各シークレットには 2 つの名前があります。`identifier` は、CLI とエージェントの `secrets` グラントで使用するハンドルです。`name` は、サンドボックス内の大文字の環境変数キーです。たとえば `STRIPE_API_KEY` です。ほとんどのプロジェクトでは、識別子と名前は一致します。1 つの名前に対して複数の候補値をプロジェクトが保持する場合に限り異なります — たとえば、Google Maps のプライマリキーとバックアップキーの両方を `GOOGLE_MAPS_API_KEY` に解決できます。

すべてのアクセスルールでは識別子を使用します。名前を使用するものはありません。

<a id="exposure-and-usage"></a>

## 公開範囲と用途

シークレットには、互いに独立した 2 つの設定があります。別々に確認してください。異なる問いに答える設定です。

| 設定 | 答える問い | 値 |
|---|---|---|
| **公開範囲** | エージェントコードは実際の値を読み取れるか？ | `environment`、`egress-enforced`、`none` |
| **用途** | 誰が使用するか？ | エージェントコード、LLM ゲートウェイ、Connector、Git |

以前の Beeuni ドキュメントでは、2 つを混在させた 1 つのリストを掲載していました。そのリストは廃止されています。「ネットワーク境界」と「HTTPS ブローカー」のどちらかを選ぶことはありません。すべてのサンドボックスプロバイダーで、egress が強制されるすべてのシークレットに 1 つの仕組みが使われます。

<a id="the-three-exposures"></a>

### 3 つの公開範囲

| 公開範囲 | サンドボックスが保持するもの | 用途 |
|---|---|---|
| **環境** | 通常の環境変数としての実際の値 | デフォルト。エージェントが計算に使う値、および HTTPS ではないプロトコル |
| **Egress 強制** | **ハンドル** — それ自体には価値のない、自己記述型のプレースホルダー | 実験的。`secrets_egress` フラグが有効な場合の HTTPS 呼び出し |
| **なし** | 何も保持しない | Beeuni のサービスだけが使用する認証情報、または保存されているが無効化された値 |

:::warning[動作上のルール]
**環境**がデフォルトの公開範囲です。実際の値がサンドボックスに読み込まれ、エージェントはそれを読み取り、表示し、転送できます。**Egress 強制**では値をサンドボックスの外部に保持しますが、実験的な機能です。使用するには `secrets_egress` 機能フラグ（Settings → Feature flags）を有効にしてください。それまでは、シークレットはサンドボックス環境に読み込まれます。
:::

<a id="usages"></a>

### 用途

用途の大半は、ユーザーではなく Beeuni が割り当てます。

- **エージェントコード** — 公開範囲が `none` でない場合は暗黙的に割り当てられます。
- **LLM ゲートウェイ** — 値が認識済みのモデルプロバイダーキーである場合に割り当てられます。ゲートウェイはプロバイダーへのリクエストをサーバー側で認証します。
- **Connector:&lt;slug&gt;** — コネクターのバインディングフローによって割り当てられます。
- **Git** — Beeuni 自身の Git アクセス用に Beeuni が割り当てます。読み取り専用で、設定や解除はできません。

公開範囲が `none` で用途がないシークレットは **無効** と表示されます。保存・暗号化はされますが、何にも使用されません。

<a id="sent-secrets-and-computed-secrets"></a>

## 送信されるシークレットと計算されるシークレット

シークレットが使用できる公開範囲は、Beeuni ではなく **上流サービス** の性質です。

- **送信されるシークレット** — 値がネットワーク上を移動します。API キー、ベアラートークン、パスワードなどです。大半がこれに該当します。値が送信リクエスト内のバイト列になる瞬間があるため、Beeuni はサンドボックスの外部で値を自ら配置できます。`secrets_egress` フラグが有効になると、送信されるシークレットは **egress 強制** に変更できます。デフォルトではサンドボックス環境に読み込まれます。
- **計算されるシークレット** — 値は計算の材料となり、ネットワーク上を移動しません。AWS SigV4 署名キー、HMAC webhook 署名シークレット、JWT クライアントアサーション、SSH 秘密鍵などです。計算する側が値を保持する必要があります。ネットワーク境界は役に立ちません。ネットワーク上に認証情報が含まれないためです。計算されるシークレットは **環境** に留める必要があります。

環境はデフォルトの公開範囲であり、サンドボックスが計算に使う必要のある認証情報を提供できる唯一の公開範囲です。非 HTTPS プロトコル — PostgreSQL の接続文字列や SMTP 認証情報など — も同じ立場にあり、環境に留める必要があります。

`AKIA…` のアクセスキーのペアや PEM/SSH マテリアルなど、署名マテリアルのように見える値を保存すると、Beeuni はデフォルトで **環境** に設定し、その理由を示します。このキーはローカルでリクエストに署名するため、egress 強制を適用できないからです。

<a id="egress-enforced-exposure"></a>

## Egress 強制の公開範囲

:::warning[実験的 — secrets_egress フラグが必要]
ネットワークでの強制は実験的な機能です。使用するには `secrets_egress` 機能フラグ（Settings → Feature flags）を有効にしてください。それまでは、シークレットはサンドボックス環境に読み込まれます。フラグが無効な状態で egress 強制のシークレットを作成すると、`403` `feature_disabled` が返されます。
:::

サンドボックスが受け取る環境変数の値は、認証情報ではなく **ハンドル** です。エージェントは、その変数を実際のキーと同じように、ヘッダー、クエリ文字列、または本文で使用します。`Authorization: Bearer $VAR`、`Cookie: …=$VAR`、`X-Api-Key` ヘッダー、クエリパラメーター、JSON またはフォーム本文のフィールドはすべて機能します。Beeuni はハンドルが現れる場所（生の文字列、URL エンコード、単独の base64、または JSON エスケープ済み）を検出し、実際の値に置き換えます。送信時に Beeuni はハンドルを実際の値に置き換えますが、承認済みのホストへのリクエストに限られます。

:::warning[ハンドルはそのまま送信 — 自分で base64 化しないでください]
機能しない方法が 1 つあります。それは、自分で作成した base64 BLOB の中にハンドルを隠すことです。**HTTP Basic 認証**がこれに該当します（`curl -u $VAR:` → `Authorization: Basic <base64>`）。Beeuni は、埋め込まれていたり、位置が揃っていなかったり、自分でエンコードした base64 の内部にあったりするハンドルを検出できません。そのため置換は行われず、上流サービスは `401` と応答します。代わりに、ハンドルを Bearer/トークンヘッダー、クエリパラメーター、または本文フィールドに入れてください。API が Basic 認証しかサポートしていない場合は、そのシークレットに **環境** 公開範囲を使用してください。
:::


この構造から、次の事実が導かれます。

- 実際の値がサンドボックス内に存在することは **決して** ありません。環境変数にも、ファイルにも、エイリアスにも存在しません。
- 承認していないホストに送信されたハンドルは、リテラルのハンドル文字列として到着します。上流サービスはそれを拒否します。価値はありません。
- 不正な署名のハンドルは決して受け入れられず、Beeuni は偽造ハンドルとして記録します。このセッションが使用できないシークレットの有効なハンドルは、盗難ハンドルとして記録されます。
- 中継されたすべてのリクエストに、リクエストごとの監査記録が書き込まれます。
- リストにないホストは読み取られずにトンネルされます。それらのホストへのピン留め TLS および mTLS クライアントは影響を受けません。

<a id="hosts-match-exactly"></a>

### ホストは完全一致します

呼び出すすべてのホストを、1 行に 1 つの正確なホスト名で列挙してください。

| 拒否されるもの | 理由 |
|---|---|
| ワイルドカードホスト、`*.example.com` | エージェントが宛先を決定してはならないため |
| HTTPS 以外の URL スキーム | Beeuni が置換のために TLS を終端するため |

`api.example.com` は `uploads.api.example.com` を対象にしません。2 つ目のホストを同じシークレットに追加してください。Beeuni は、保存時に強制できないポリシーを `400` で拒否します。適用できないルールを保存することはありません。

送信先制限付きシークレットは、同じホストを共有できます。各ハンドルは個別の値に対応するため、同じリクエスト内でも両方が正しく置換されます。

<a id="verify-it-with-two-probes"></a>

### 2つのプローブで確認する

両方のプローブをサンドボックス内から、リストに登録されているホストに対して実行します。この例では、各種類のエンドポイントを1つずつ提供する `postman-echo.com` を使います。テスト中は、許可ホストとして追加してください。

```bash
# 1. Reachability — an endpoint that does NOT echo request headers.
curl -s -o /dev/null -w '%{http_code}\n' https://postman-echo.com/status/200
# expected: 200

# 2. Substitution — an endpoint that DOES echo request headers.
curl -sS -H "authorization: Bearer $STRIPE_API_KEY" https://postman-echo.com/get
# expected: 200, with "Bearer [REDACTED]" in the echoed headers
```

2つの結果を合わせて確認し、プローブ1を先に実行してください。ホストに到達できるかどうかが分かるのはプローブ1だけです。プローブ1が成功するまでは、プローブ2では何も確認できません。

| プローブ2の結果 | 意味 |
|---|---|
| `200`。エコーされたヘッダーに `[REDACTED]` と表示される | 正常です。実際の値が上流に送信され、応答が返る際にエコーが伏せられています。 |
| `200`。エコーされたヘッダーにハンドルそのものが表示される | 置換が実行されていません。ホストリストとエージェントへの許可を確認してください。 |
| 実際のAPIホストから `401` が返る | 置換が実行されていません。同じ2項目を確認してください。 |
| 空の応答または接続エラー | 実際の失敗です。成功を示す症状ではありません。 |

ゲスト環境内のどこにも実際の値がないことを確認します。

```bash
env | grep '^STRIPE_API_KEY='
# expected: the handle, not the credential
```

識別子は `BEEUNI_SECRET_CAPABILITIES` にも表示されます。これは、どのシークレットが存在するか、各ハンドルがどの変数に入るか、それぞれがどのホストを対象とするかをエージェントに伝える、値を含まないカタログです。値が含まれることはありません。

リストに登録されたホストにアクセスすると、オリジン独自の証明書ではなく、Beeuniがこのサンドボックス用に発行した証明書が提示されます。この証明書はサンドボックスで既に信頼されています。

```bash
curl -sv https://postman-echo.com/status/200 2>&1 | grep 'issuer:'
# issuer: CN=Beeuni Egress CA (<project prefix>); O=Beeuni
```

<a id="what-the-relay-changes"></a>

### リレーによる変更点

許可されたホストへのアクセスはBeeuni経由になるため、直接呼び出す場合とは少し異なります。

- 応答はストリーミングされません。許可ホスト経由では、Server-Sent EventsとWebSocketは機能しません。
- リクエスト本文は1 MiB、応答は5 MiB、呼び出し全体は30秒が上限です。Beeuniがたどるリダイレクトは最大3回です。
- 返される応答ヘッダーは、コンテンツタイプと言語、キャッシュ検証子、レート制限関連、`retry-after`、`x-request-id` のみに限られます。
- `https_proxy` を尊重するクライアントのみがインターセプトされます。Beeuniはこの変数と対応するCA信頼設定をエージェントの環境に設定します。環境を消去して起動したプロセスはホストを直接呼び出すため、ハンドルを含んだリクエストが送信されます。

Beeuniがインターセプトできないリクエストに対しても、エージェントには同じポリシーのもと、同じホストにアクセスするための明示的な経路があります。

```bash
beeuni secrets call STRIPE_API_KEY https://api.stripe.com/v1/customers
```

<a id="environment-exposure"></a>

## 環境変数への露出

サンドボックスには、実際の値が通常の環境変数として渡されます。エージェントのコードはその値を読み取り、表示し、どこへでも転送できます。Beeuniはその値を伏せることも、使用状況を監査することも、外部への送信を止めることもできません。

デフォルトの露出方法は環境変数です。新しいシークレットはすべて、送信先制限付きに切り替えるまでこの方式を使います。送信先制限付きは試験運用中で、`secrets_egress` フラグが必要です。計算によって生成される認証情報と、HTTPS以外のプロトコルは、環境変数を使う必要があります。

<a id="who-can-use-a-secret"></a>

## シークレットを使用できる人

各シークレットの値には、コネクタアカウントと同じ **使用できる人** の選択肢が適用されます。

| 選択肢 | 値を使用できる人 |
| --- | --- |
| **プロジェクトの全員**（デフォルト） | トリガー、スケジュール、共有セッションを含む、プロジェクト内のすべてのセッション。 |
| **自分のみ** | あなた本人と、あなた自身のプライベートセッション。 |
| **特定の人、グループ、またはエージェント** | 選択した人とグループ（本人が直接使う場合と、それぞれのプライベートセッション）、および選択したエージェント（そのすべてのセッション）。 |

セッションは常に**エージェント**として、また、プライベートな間だけ**人**として扱われます。

- **人**は、自分が開始した**プライベート**セッションで値を使用できます。他の人からプロンプトが届くと、そのセッションからその人の情報が削除されるため、値を使えなくなります。共有セッション、トリガー、スケジュール、Webhook、メール、Telegramのセッションには人の情報がありません。
- **エージェント**は、そのエージェントのすべてのセッションで値を使用できます。トリガー、スケジュール、共有セッションも含まれます。無人実行で値が必要な場合は、エージェントに値を共有してください。そのエージェントを実行できる人は誰でも、エージェントを通じて値を使えます。つまり、ゲートとなるのはエージェントの実行権限です（エージェントの実行権限はエージェント上で設定します）。
- サーバー側の利用者にも同じルールが適用されます。シークレットに紐づいたコネクタは、利用者が対象者の場合に限り値を使用します。それ以外の利用者には `credential_not_shared` が返され、Beeuniからリクエストが送信されることはありません。
- Gitプロキシ、Webhook署名チェック、チャンネルのインストール、Beeuni Appsなど、誰の代理でもないBeeuniのサービスは、全員と共有された値のみを使用します。

同じ名前で複数の値を共有できます。セッションの人と共有された値は、そのエージェントと共有された値より優先され、エージェントと共有された値は、全員と共有された値より優先されます。例：`DEEL_API_TOKEN` にはチーム用の値があり、識別子 `DEEL_API_TOKEN-finance` にはFinanceグループとのみ共有された別の値があります。FinanceのメンバーはプライベートセッションでFinance用の値を使い、それ以外の人とすべてのトリガーはチーム用の値を使います。

対象者を設定できるのは人だけです。エージェントのセッションから対象者を変更することはできないため（`403`）、エージェントが自分に共有されていない値の対象者を広げたり、自分を追加したりすることはできません。プロジェクトのシークレットを管理する人には、自分と共有されていない値も **あなたには共有されていません** と表示されます。これにより、対象者を再び広げることができます。

<a id="sharing-a-session-that-holds-a-personal-value"></a>

### 個人用の値を含むセッションを共有する

自分のみと共有された値が**環境変数**としてプライベートセッションに渡されると、そのサンドボックス内では平文になります。そのセッションを共有すると、新しい閲覧者全員が値を読めてしまいます。また、実行中のサンドボックスから環境変数を取り除くことはできません。そのためBeeuniは、`409 PERSONAL_SECRET_REQUIRES_PRIVATE_SESSION` と、そのセッションに含まれる名前がある場合、そのセッションの共有や公開リンクの作成を拒否します。共有するには新しいセッションを開始するか、先に値を全員と共有してください。エージェント経由で使われる値と、送信先制限付きまたはサーバー側の値（リクエストごとに確認されます）は、共有を妨げません。

対象者を狭めると、Beeuniは実行中のすべてのサンドボックスに再度値を渡します。環境変数として既に渡された値は、再起動するまでサンドボックス内に残ります。値が読み取られた可能性がある場合は、ローテーションしてください。

<a id="when-you-enter-a-value-through-a-link"></a>

### リンクから値を入力する場合

必要な値をまだ受け取っていないエージェントは、リンクを送ります。リンク先のページで **使用できる人** を選択できます。プロジェクトの全員（デフォルト）または、依頼した人のみです。給与トークンや個人用ログイン情報など、個人的な値には2つ目を選んでください。リンクを持つ人なら誰でも開けるため、ページには依頼した人のメールアドレスではなく、表示名のみが記載されます。

<a id="personal-override"></a>

### 個人用の上書き

個人用の上書きとは、1つの名前に対して共有値の代わりに使う、あなた自身の値です。現在、Beeuniで個人用の上書きとして使えるのは、OAuthログイン認証情報1つのみです。たとえば`ANTHROPIC_API_KEY`のようなLLMプロバイダーキーを、Beeuniが個人用の上書きにすることは決してありません。

<a id="add-a-secret"></a>

## シークレットを追加する

1. **CLIから値を設定する**

    ```bash
    beeuni secrets set STRIPE_API_KEY=sk_live_...
    ```

    Beeuniはプロジェクトの全員が使えるように値を保存します。自分のみが使えるようにするには、`--only-me` を追加します。同じ名前で複数の値を保存するには、`--identifier <id>` を追加します。名前を `BEEUNI_` で始めることはできません。この接頭辞はプラットフォームの値用にBeeuniが予約しています。

    後から使用者を変更するには、次のようにします。

    ```bash
    beeuni secrets share DEEL_API_TOKEN --user me
    beeuni secrets share DEEL_API_TOKEN --user finance@example.com --group <group-id>
    beeuni secrets share NIGHTLY_REPORT_TOKEN --agent reporter
    beeuni secrets share DEEL_API_TOKEN --everyone
    ```

2. **またはダッシュボードを使う**

    プロジェクトの Secrets ページを開き、キーと値を入力して、**使用できるユーザー**を選び、保存します。Beeuni は値を直ちに暗号化し、新しいシークレットはすべて、デフォルトで**プロジェクト内の全員**に**環境**公開されるよう設定します。実際の値はサンドボックスに読み込まれます。**使用できるユーザー**列には、それぞれの値の対象ユーザーが表示されます。

    シークレットを送信先制限付きの公開に変更するには、まず `secrets_egress` 機能フラグ（Settings → Feature flags）を有効にします。この機能は実験的です。フラグを有効にすると、Secrets ページに**「コードからこの値を読み取れますか？」**コントロールが表示されます。*いいえ*を選ぶと、シークレットは送信先制限付きに変更され、ホストのリストが表示されます。*はい*を選ぶと、環境公開のままになります。フラグが無効の場合、シークレットは環境公開のままです。

3. **エージェントに付与する**

    Secrets ページでエージェントを選ぶか、エージェントの `secrets` リストに識別子を自分で追加します（`beeuni.yaml` 内）。セッションが受け取るのは、そのエージェントに付与されたシークレットだけです。[エージェントにシークレットを付与する](#grant-a-secret-to-an-agent)を参照してください。

<a id="grant-a-secret-to-an-agent"></a>

## エージェントにシークレットを付与する

セッションがシークレットを受け取るのは、実行するエージェントが `secrets` リストに識別子を指定している場合だけです。一致判定には名前ではなく識別子が使われ、大文字と小文字は区別されません。

:::warning[送信先制限付きおよびサービス利用のシークレットには明示的な付与が必要です]
`secrets: all` が付与するのは環境公開だけです。送信先制限付きのシークレットと、Beeuni サービスが使用するシークレットは、いずれもエージェントのリストに識別子を明記する必要があります。`beeuni.yaml` に `agents:` ブロックがないプロジェクトは、シークレットを一切受け取りません。付与されていないシークレットは通知なしで除外されます。セッションは通常どおり開始しますが、ホストへの最初の呼び出しは、認証情報が間違っている場合と同じように失敗します。
:::

<a id="from-the-dashboard"></a>

### ダッシュボードから

Secrets ページでは、どのエージェントも受け取れないシークレットに **このシークレットを受け取れるエージェントはいません** と表示されます。そこでエージェントを選び、確定します。Beeuni は `beeuni.yaml` を編集し、`chore(agents): grant <IDENTIFIER> to <agent>` としてコミットします。

マニフェストにエージェントがすでに宣言されているかどうかにかかわらず、付与は機能します。マニフェストに宣言されていないエージェントには、この `secrets` リストだけを含む新しいエントリが作られます。すでに宣言されているエージェントでは、モデル、ツール、コネクタなどの他のフィールドはすべてそのまま維持され、識別子が既存のリストに追加されます。エージェントがすでにその識別子を許可している場合、コミットは不要で、Beeuni は何も変更しません。

エージェントが `secrets: all` 上にある場合は特別です。`all` には送信先制限付きのシークレットを指定できないため、Beeuni は明示的なリストを書き込みます。リストには、プロジェクトに現在あるすべての識別子と、この識別子が含まれます。エージェントが現在受け取っている内容は変わりません。後から追加したシークレットには、別途付与が必要です。

付与できないケースは2つあります。

- `beeuni_version: 1`（`beeuni.toml`）を使用するプロジェクトには、編集するエージェントマップがありません。リクエストは `400` と `manifest_v1_unsupported` で失敗します。マニフェストを手動で編集するか、プロジェクトを `beeuni_version: 2` に移してください。
- **無効**になっているシークレットは配信できません。リクエストは `409` と `secret_not_grantable` で失敗します。先に公開設定を付与してください。

プロジェクトにまだ `agents:` ブロックがない場合は、確定する前に[最初の `agents:` ブロックがプロジェクト全体を変える](#the-first-agents-block-changes-the-whole-project)をお読みください。その変更ひとつで、他のすべてのエージェントのシークレットアクセスが変わります。

<a id="by-hand"></a>

### 手動で行う

同じ付与を直接記述すると、次のようになります。

```yaml
beeuni_version: 2
agents:
  my-agent:
    secrets: [STRIPE_API_KEY]
```

<a id="when-a-session-asks-for-a-secret-its-agent-is-not-granted"></a>

### セッションが、エージェントに付与されていないシークレットを要求した場合

認証情報が必要なエージェントは、シークレットリンク（`beeuni secrets request`）を作成します。入力した値は、セッションのエージェントにそのシークレットが付与されていなくても保存されます。そのセッションには届かないため、Beeuni はあらゆる画面でそのことを伝えます。

- リンクのフォームには **保存しましたが、`<agent>` はまだ読み取れません** と表示され、シークレット名が示されます。
- シークレットを付与する方法とともに、作成時の応答とセッションへのフォローアップメッセージに `withheld` 名が記載されます。
- セッション内では、`beeuni secrets ls` に、付与されていない宣言済みのキーが `not granted` と表示され、`missing` とは表示されません。

エージェントが自分で付与範囲を広げることはできません。**Customize → Agents → `<agent>` → Secrets** を開き、シークレットを有効にしてください。保存すると、Beeuni は変更をエージェントの実行中セッションに反映します。エージェントは `beeuni secrets sync` で直ちに取得することもでき、プロンプトのたびにセッションのシークレットが同期されます。再起動は不要です。

<a id="the-first-agents-block-changes-the-whole-project"></a>

### 最初の `agents:` ブロックがプロジェクト全体を変える

:::warning[エージェントを1つ宣言すると、他のエージェントは拒否されます]
`agents:` ブロックがないプロジェクト、または `beeuni.yaml` がまったくないプロジェクトは、アクセス制御されていません。すべてのエージェントが環境公開のシークレットをすべて受け取り、送信先制限付きのシークレットはどのエージェントにも届きません。

プロジェクトで最初のエージェントを宣言した時点で、リストにないエージェントは、直前まで使えていた環境シークレットを含め、プロジェクトのシークレットを一切受け取れなくなります。1つのエージェントをリストに追加すると、他のエージェントへの付与は取り消されます。
:::

そのため、修正するエージェントだけでなく、シークレットが必要なエージェントをすべてリストに追加してください。初回にダッシュボードで確認を求めるのはこのためです。このコミット以降、`agents:` がプロジェクトの許可リストとなり、リストにないエージェントはプロジェクトのシークレットを持たずに実行されます。

<a id="exposing-capabilities-to-third-party-users"></a>

## サードパーティユーザーに機能を公開する

:::warning[Beeuni のシークレットポリシーは、マルチテナントの認可システムではありません]
シークレットポリシーは、**プロジェクト自身のエージェント**が**プロジェクト自身の認証情報**を漏えいさせないためのものです。エンドユーザーのうち、誰がそれを使用できるかについては何も定めません。
:::

**信頼できないサードパーティユーザー**が機能を利用できるもの、たとえば公開チャット、共有アプリ、インターネット上の誰もがプロンプトを送れるエージェントを構築している場合、シークレットポリシーをそのまま適用してはいけません。その画面を利用するすべてのユーザーが、1つのプロジェクトエージェント、1つの付与、1つのホストリストを共有します。Beeuni は顧客同士を区別できません。そのため、ユーザーのプロンプトからアクセスできる送信先制限付きシークレットは、上流のキーが持つ最大限の権限まで、すべてのユーザーが使用できる認証情報になります。

必要な境界は、ご自身で構築してください。

1. 独自の認可サービスとプロキシサービスを構築します。上流の認証情報はそのサービスで保持します。
2. エージェントは上流ではなく、自分のサービスに接続させます。エージェントには自分のサービス用の認証情報だけを渡し、その認証情報は自分のホストへの送信に制限できます。
3. サービス側でエンドユーザーを特定し、独自の認可ルールとユーザーごとのクォータを適用してから、保持している認証情報を使って上流を呼び出します。

ユーザーごとのルール、つまり誰が何をどのくらいの頻度で、どのレコードに対して呼び出せるかを定めるのは、このサービスです。Beeuni のシークレット公開設定はその一段下のレイヤーであり、代わりにはなりません。

<a id="list-your-secrets"></a>

## シークレットを一覧表示する

`beeuni secrets ls` を実行すると、プロジェクトが宣言しているシークレットと、値が設定されているシークレットを確認できます。

一覧に表示されるのは設定メタデータです。シークレットの値は返されません。スコープ付きエージェントトークンに表示されるのは、そのエージェントに付与された識別子だけです。セッション固有の `secrets_allowlist` は、そのセッションへの配信を制御しますが、エージェントへの付与で許可された設定メタデータを非表示にはしません。

<a id="rotate-a-secret"></a>

## シークレットをローテーションする

1. **新しい値を設定する**

    同じコマンドで新しい値を指定するか、プロジェクトの Secrets ページで設定し直します。

    ```bash
    beeuni secrets set STRIPE_API_KEY=sk_live_new...
    ```

2. **Beeuniは実行中のセッションに反映します**

    Beeuniはベストエフォートで、プロジェクトのアクティブなセッションがあるすべてのサンドボックスに変更を反映します。
    モデルまたはゲートウェイの認証情報の場合、Beeuniは標準ハーネス互換プロセスを再起動します。

    送信先を制限したシークレットのローテーションでは、値をプッシュする必要はありません。サンドボックスにはハンドルが保持され、次のリクエストが届いたときにBeeuniが最新の値を読み取ります。

<a id="remove-a-secret"></a>

## シークレットを削除する

`beeuni secrets unset STRIPE_API_KEY`（または`unset <identifier>`）を実行するか、プロジェクトのSecretsページから削除します。

:::warning[削除は即時、反映には時間がかかる場合があります]
Beeuniは共有シークレットをすぐに削除します。すでに実行中のサンドボックスへのプッシュは、ローテーションと同様にベストエフォートです。
:::

<a id="share-a-value-without-seeing-it"></a>

## 値を見ずに共有する

`beeuni secrets request STRIPE_API_KEY`を実行してリンクを作成します。リンクを知っている人は誰でも値を入力できます。あなたが値を見ることはありません。リンクはデフォルトで7日間有効です。`--expires <minutes>`で期間を変更できます（最長30日）。期限切れのリンクには「期限切れ」と明示されたページが表示されます。同じコマンドで新しいリンクを作成してください。

<a id="give-an-agent-a-value-directly"></a>

## エージェントに値を直接渡す

セッションでキーを貼り付けると、エージェントは`beeuni secrets set`を使ってすぐに保存します。リンクは送信されません。エージェントにはプロジェクトのシークレット書き込み権限が必要です。権限がない場合、エージェントは`403`を受け取り、代わりにシークレットリンクを作成します。エージェントは環境シークレットまたはコネクターシークレット（`--scope connector`）を保存できます。送信先の制限とホストリストの設定は、人間のみが行えます。

<a id="end-to-end-example"></a>

## 使用例

`beeuni.yaml`:

```yaml
beeuni_version: 2
default_agent: my-agent
agents:
  my-agent:
    secrets: [STRIPE_API_KEY]
```

シークレットの設定。最初のコマンドは、デフォルトの環境への公開設定で値を保存します。2つ目のコマンドは、送信先を制限した公開設定に変更します。この機能は実験的で、`secrets_egress`フラグ（Settings → Feature flags）が必要です。フラグがオフの場合は`403` `feature_disabled`を返します。

```bash
beeuni secrets set STRIPE_API_KEY=sk_live_...
beeuni secrets delivery STRIPE_API_KEY egress --allow-host api.stripe.com
```

その後、エージェントは渡された変数を使ってStripeを呼び出します。

```bash
curl -s -o /dev/null -w '%{http_code}\n' \
  -H "authorization: Bearer $STRIPE_API_KEY" \
  https://api.stripe.com/v1/customers
# expected: 200
```

`$STRIPE_API_KEY`にはハンドルが保持されます。`api.stripe.com`はリストに含まれているため、Stripeには実際のキーが届きます。リストにないホストへの同じリクエストではハンドルが送信され、上流側で拒否されます。

`secrets`リストに`STRIPE_API_KEY`が含まれていないエージェントから同じリクエストを送ると、`401`が返されます。そのセッションは通常どおり開始します。許可されていないシークレットはエラーになるのではなく、まったく配信されません。

<a id="cli-commands"></a>

## CLIコマンド

| コマンド | 内容 |
|---|---|
| `beeuni secrets ls` | プロジェクトで宣言・設定されているシークレットを一覧表示する |
| `beeuni secrets set KEY=VALUE [--identifier <id>] [--scope runtime\|connector]` | シークレットを作成または更新する。`KEY=-`は標準入力から値を読み取る。`--scope connector`は値をサーバー側に保持する |
| `beeuni secrets unset IDENTIFIER` | シークレットを削除する |
| `beeuni secrets delivery IDENTIFIER egress --allow-host <host>` | 指定したホストに送信先を制限して公開する。実験的な機能で、`secrets_egress`フラグが必要 |
| `beeuni secrets delivery IDENTIFIER runtime` | 環境に公開する（デフォルト） |
| `beeuni secrets delivery IDENTIFIER denied` | 無効にする |
| `beeuni secrets call IDENTIFIER URL` | ポリシーに従ったHTTPSリクエストをBeeuni経由で1件送信する。実験的な機能で、`secrets_egress`フラグが必要 |
| `beeuni secrets sync` | エージェントセッション内では、このセッションのシークレットを取得して今すぐ許可する。ユーザーとして実行する場合は、プロジェクトのすべてのアクティブなサンドボックスに再プッシュする |
| `beeuni secrets request NAME [--scope runtime\|connector] [--expires <min>]` | 他の人が値を入力できるリンクを作成する |
| `beeuni env push --from <path>` | `.env`ファイルをシークレットとしてアップロードする |
| `beeuni env pull [--out <path>] [--force]` | 値ではなくシークレット名を`.env`ファイルにエクスポートする |

CLIでは保存済みの用語が使われます。`runtime`は環境への公開、`egress`は送信先の制限、`denied`は無効を表します。すべてのフラグは`beeuni secrets --help`で確認できます。

セットアップリンクはデフォルトで`connector`です。エージェントのシェルに値を渡す必要がある場合に限り、`--scope runtime`を使います。コネクターに紐付けられたシークレットはサーバー側に保持されます。

<a id="names-and-permissions"></a>

## 名前と権限

2種類の名前の形式ルールは次のとおりです。

| 名前 | 形式 |
|---|---|
| `identifier` | `^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$` |
| `name` | `^[A-Z_][A-Z0-9_]{0,63}$` |

シークレットの読み取りまたは書き込みには、`project.secret.read`または`project.secret.write`の権限が必要です。プロジェクトマネージャーは両方の権限を持ちます。カスタムロールで追加できるのは権限のみです。Beeuniには拒否ルールがないため、マネージャーからどちらかの権限を取り上げることはできません。マネージャーを制限するには、マネージャーロールを削除してください。

セッションへの配信は、開始したユーザーのロール判定と、起動したエージェントのマニフェストによる許可の両方を満たす必要があります。双方がシークレットの使用を許可していなければなりません。[1つの用語、2つの紐付け](/docs/ja/accounts#one-vocabulary-two-bindings)を参照してください。

<a id="rest-routes"></a>

## RESTルート

すべてのルートは`/v1/projects/{projectId}`以下にあります。

| メソッド | パス | 説明 |
|---|---|---|
| GET | `/secrets` | シークレットを一覧表示する。呼び出し元がスコープ付きエージェントトークンの場合は、その許可範囲に限定される。 |
| POST | `/secrets` | 共有値を作成または更新する。本文: `{name, identifier?, value}`。任意で配信ポリシーも指定できる。 |
| PUT | `/secrets/{identifier}/strategy` | 公開設定とホストリストを変更する。 |
| POST | `/secrets/{identifier}/grant` | `beeuni.yaml`内の1つのエージェントの`secrets`リストに識別子を追加する。本文: `{agent}`。 |
| DELETE | `/secrets/{name}` | 共有値を削除する。個人用の上書き設定はそのまま残る。 |
| PUT | `/secrets/{name}/personal` | 呼び出し元の個人用上書き設定を設定または有効化する。 |
| DELETE | `/secrets/{name}/personal` | 呼び出し元の個人用上書き設定を削除する。 |

`POST /secrets`は`BEEUNI_`で始まる名前を拒否します。`identifier`がすでに存在し、`name`が異なる場合は`409`を返します。正確な名前が`CODEX_AUTH_JSON`の場合は`400`で拒否します。このシークレットはBeeuniがChatGPTのサブスクリプション登録を通じて管理します。

いずれかの書き込みルートで、実行中のサンドボックスへの変更反映が必要だった場合は、`delivery_sync`オブジェクトが返されます。`ok: false`は値が保存されたものの、少なくとも1つのライブセッションがまだ以前の値を使用していることを意味します。一覧にあるセッションは再起動時に新しい値を反映します。

シークレットの一覧項目には`delivery_blocked_reason`が含まれます。値が`no_agent_grant`の場合、このシークレットを受け取れるエージェントはいません。`null`の場合は、許可済みである、公開設定に許可が不要である、またはBeeuniがマニフェストを読み取れなかったことを示します。

`POST /secrets/{identifier}/grant`はその理由を解消します。エージェントのリストですでに識別子が許可されている場合は`already_granted: true`を返し、その場合Beeuniは変更を確定しません。編集によってプロジェクトに初めて`agents:`ブロックが追加された場合は`adopted_governance: true`を返します。この変更については[上記の説明](#grant-a-secret-to-an-agent)を参照してください。`beeuni.toml`プロジェクトでは`400` `manifest_v1_unsupported`、無効なシークレットでは`409` `secret_not_grantable`を返します。

<a id="rotation-and-propagation"></a>

## ローテーションと反映

シークレットの書き込みは、セッションの再起動を待ちません。Beeuniはプロジェクト内のすべてのアクティブなサンドボックスに変更を反映します。

1. Beeuniは実行中のエージェントの`secrets`許可を使って、新しい環境スナップショットを作成します。
2. サンドボックスはスナップショットをライブエージェント環境に書き込みます。新しいツール呼び出しにはすぐに変更が反映されます。
3. 変更されたシークレットがLLMプロバイダーの認証情報の場合、Beeuniは標準ハーネスを再起動します。

このプッシュはベストエフォートです。シークレットを変更するAPI呼び出しは、プッシュの完了を待たずに返ります。プッシュが失敗してもログに記録されるだけで、再試行されません。プッシュに失敗したサンドボックスは、次回のプッシュが成功するか、セッションが再起動するまで古い値を使い続けます。

<a id="model-credentials"></a>

## モデル認証情報

Beeuniの管理するモデルアクセスを利用するプロジェクトには、独自のキーは不要です。独自のキーを使う場合は、標準ハーネスのプロバイダー設定で参照されているプロバイダー変数を設定してください。認識されたモデルキーには**LLMゲートウェイ**用途が割り当てられ、サーバー側で使用されます。サンドボックスに置く必要はありません。

汎用プロバイダーの検証結果を、実行時の動作の証明として使わないでください。選択したモデル、リージョン、利用資格、API仕様を確認することはできません。実際に使用するモデルに対して、実際のプロンプトを送信してください。
