Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions README.ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ Claude Code を複数の部署に展開すると、部署ごとに許す範囲

Claude Code は自身の権限ルールをフックより先に評価します。だからこの設定ファイルは、手で保守するのではなく生成する価値があります。

**判断は作業中に個人ごとではなく、ここで部署単位に一度だけ行う。** 確認プロンプトが守ってくれるのは、その内容を判断できる人だけです。この役割定義の対象者は、別の作業の途中でシェルコマンドの是非を裁定する立場にありません。実際には、非エンジニアは全部許可して確認の意味をなくすか、全部拒否して仕事が止まるかのどちらかになります。そのため `shell` は `none` と `unrestricted` の2値で、中間の allowlist を置いていません。`packages` に `approved` がないのも同じ理由です。特定の npm パッケージの是非は、文脈を持った状態で部署単位に決めることで、作業中の割り込みで決めることではありません。コマンド単位の確認が必要な場合は、その `ask` ルールを手で書いてください。生成されるファイルは編集可能な出発点です。

**どの組み合わせでも緩められない部分。** 認証情報ファイル、SSH 鍵、`rm -rf`、ダウンロードのシェルへのパイプは、6項目をどう設定しても拒否されます。これを正しく作るには、直感に反する制約が1つ必要でした。capability のルールはベースラインより*先*に評価されるため、`git push*` に対して無条件の許可を出す軸があると、それがベースライン側の `*--force*` 拒否より前に置かれ、force-push が静かに再開されてしまいます。そのため `git` は on/off ではなく3値(`none` / `local` / `push`)で、`push` でも force-push は拒否されたままです。さらに [テスト](tests/test_profiles.py) が「許可を出せる軸は `git` だけ」であることを検証しています。

[`profiles/`](profiles/) の3つの役割定義は出発点であって答えではありません。「マーケティング部とは何か」についての前提が入っており、それはおそらく自社には合いません。コピーして書き換えて使ってください。破壊的変更の全リスト(`--policy` 廃止、`[server]` extra 廃止、未リリースだった3サブシステムの削除)は [v2.0.1 リリースノート](https://github.com/killertcell428/aigis/releases/tag/v2.0.1) を参照してください。

---
Expand Down Expand Up @@ -165,10 +169,10 @@ v1.2 では **ANSI エスケープに隠した命令**(目に見えないタ

| 情シスの問い | Aigis の答え | コマンド |
|---|---|---|
| 何を実行できるのか? | 決定論的ポリシーがすべての Bash/Edit/Write/WebFetch を実行前にスキャンし、拒否された操作はブロック(exit 2)されシェルに到達しません。同梱ルールは拒否リスト方式のため、どのルールにも該当しない操作は通ります。fail-closed が要件なら `default_decision: deny` と許可ルールの設定が必要です。 | `aigis init --agent claude-code --signed-audit` |
| 何を実行できるのか? | 決定論的ポリシーがすべての Bash/Edit/Write/WebFetch を実行前にスキャンし、拒否された操作はブロック(exit 2)されシェルに到達しません。同梱ルールは拒否リスト方式です。`ls` すら動かないエージェントは使い物にならないため、どのルールにも該当しない操作は通します。fail-closed が要件なら `default_decision: deny` と明示的な許可ルールを設定してください。ただしその許可ルールを列挙する作業は相応の工数になります。 | `aigis init --agent claude-code --signed-audit` |
| 組織全体にどう強制するのか? | `aigis settings --managed` が Aigis のポリシーから Claude Code 自身の権限ルールを生成します。2つのファイルを別々に手で保守するのではなく、1つの設定から両方を導出できます。managed ルールはコマンドライン引数を含むどの設定レベルからも上書きできません。正確に表現できないルールは、近似せず警告して除外します。 | `aigis settings --managed` |
| ログはどこにあるのか? | ツール呼び出し層の、スキーマが安定したマシンレベル監査ログ。Claude Code のどのプランでも残せます。 | `aigis logs --export-excel` |
| ログは改ざんできないか? | 各レコードは HMAC 署名 + ハッシュチェーンで連結され、1 行でも改変・削除されると検証が明確に失敗します。 | `aigis audit verify` |
| ログは改ざんできないか? | 各レコードは HMAC 署名 + ハッシュチェーンで連結され、1 行でも改変・削除されると検証が明確に失敗します。既定では鍵がエージェントと同じマシン上にあるため、そのマシンの利用者本人が監査対象に入る場合は SIEM 転送と併用してください([詳細](#鍵の置き場所が署名で証明できる範囲を決める))。 | `aigis audit verify` |
| どの標準に対応しているか? | ISO/IEC 27001:2022 附属書 A・NIST AI RMF・OWASP LLM Top 10・経産省 AI 事業者ガイドラインへのコントロールマトリクスと、ライブの OWASP スコアカード。 | `aigis trust-pack` · `aigis monitor --owasp` |
| インシデント時はどうするのか? | パックに NIST SP 800-61 準拠のインシデント Runbook を同梱。週次ダイジェストで管理者にも共有できます。 | `aigis report weekly` |

Expand All @@ -185,6 +189,16 @@ Aigis は Claude Code 自身のエンタープライズ機能を置き換える

Claude Code の Team プランには監査ログ API がなく、Enterprise の OpenTelemetry エクスポートはメトリクス用途です。ダッシュボードには有用ですが、調査に耐えるエビデンスとして設計されたものではありません。Aigis のフックは、プランに関わらずマシンレベルでスキーマ安定・改ざん検知つきのログを生成するため、プラットフォーム側が記録を提供しない場面でも防御可能な記録を手元に残せます。

### 鍵の置き場所が署名で証明できる範囲を決める

既定では HMAC 鍵はエージェントと同じマシンの `.aigis/audit_key` に自動生成されます。したがって署名が証明するのは「その鍵ファイルを持たない者による改変がなかったこと」です。これは一見より弱い主張で、エージェントを動かしている開発者本人は鍵を持っています。ローカル署名で捕まえられるのは外部からの書き換えであって、ログの作成者自身ではありません。

この境界は、次の3つで動かせます。カバー範囲の狭い順です。

- 自動生成ファイルを使わず、明示的な鍵(`SignedAuditLog(secret_key=...)`)を渡す。CI から注入する、シークレットマネージャから読むなど、開発者の手の届かない場所に置く
- 鍵ファイルへのアクセスを制限する。Aigis は OS が対応していれば POSIX パーミッションを設定しますが、Windows では `chmod` が効かないため NTFS ACL を自分で設定する必要があります
- イベントをマシン外に転送する。Splunk・Datadog・Sentinel・Elastic にレコードが複製されれば([docs/forwarders.md](docs/forwarders.md))、ローカルのコピーを書き換えてもエビデンスは変わりません。監査対象がそのマシンを使っている本人である場合に効くのは、この対策です

### なぜ独立した OSS レイヤーなのか

2025–26 年の買収の波で、独立した選択肢は薄くなりました。Protect AI は Palo Alto に、Invariant Labs の mcp-scan は Snyk に、Lakera は Check Point に、promptfoo は OpenAI に買収されています。Aigis は独立かつ Apache-2.0 のままです。すべてのルールを読め、自社の CI で動かせ、次に買収されるかもしれないベンダーに統制基盤を委ねずに済みます。
Expand Down
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,10 @@ Rolling Claude Code out past one team means different permissions per team — m

Claude Code checks its own permission rules before any hook runs, which is why that file is worth generating rather than leaving to hand-maintenance.

**Judgement happens here, once, for the whole group — not mid-task, per person.** A prompt only protects someone who can judge it, and these roles are for people who are not in a position to rule on a shell command while they're in the middle of something else: in practice a non-engineer either approves everything, which defeats the prompt, or refuses everything, which stops their work. That is why `shell` is `none` or `unrestricted` with no allowlist in between, and why `packages` has no `approved` value — whether a specific npm package is acceptable is a decision to make with context, for a team, not an interruption. If you do want per-command prompting, write those `ask` rules by hand; the generated file is a starting point you can edit.

**What no combination can weaken.** Credential files, SSH keys, `rm -rf`, piping a download into a shell stay denied regardless of the six values. Getting that right required one non-obvious constraint: capability rules are evaluated *before* the baseline, so any axis emitting a blanket allow for `git push*` would place it in front of the baseline's own `*--force*` deny and quietly re-enable force-push. So `git` has three values (`none`, `local`, `push`) rather than an on/off switch, `push` still blocks force-push, and [a test](tests/test_profiles.py) asserts `git` is the only axis permitted to emit an allow at all.

The three roles in [`profiles/`](profiles/) are starting points, not answers — they encode assumptions about what "marketing" means that are probably wrong for your company. Copy one and edit it. See the [v2.0.1 release notes](https://github.com/killertcell428/aigis/releases/tag/v2.0.1) for the full breaking-change list (`--policy` removed, the `[server]` extra removed, three unreleased subsystems dropped).

---
Expand All @@ -161,10 +165,10 @@ Approving an autonomous agent comes down to a handful of questions. Aigis is bui

| What IT asks | Aigis answer | Command |
|---|---|---|
| What can it execute? | A deterministic policy scans every Bash/Edit/Write/WebFetch before it runs; denied actions are blocked (exit 2) and never reach the shell. The shipped rules are a deny-list, so an operation no rule covers proceeds — set `default_decision: deny` plus allow rules if your review requires fail-closed. | `aigis init --agent claude-code --signed-audit` |
| What can it execute? | A deterministic policy scans every Bash/Edit/Write/WebFetch before it runs; denied actions are blocked (exit 2) and never reach the shell. The shipped rules are a deny-list — an agent that can't run `ls` is not usable, so anything no rule covers proceeds. If your review requires fail-closed, set `default_decision: deny` plus explicit allow rules; enumerating those rules is real work, so budget for it. | `aigis init --agent claude-code --signed-audit` |
| How do we enforce it org-wide? | `aigis settings --managed` derives Claude Code's own permission rules from your Aigis policy, so both come from one file instead of two hand-maintained ones. Managed rules cannot be overridden by any other settings level, not even command line arguments. Rules that can't be expressed exactly are reported, never approximated. | `aigis settings --managed` |
| Where are the logs? | Schema-stable, machine-level audit logs at the tool-call layer, on any Claude Code plan. | `aigis logs --export-excel` |
| Can the logs be tampered with? | Each record is HMAC-signed and hash-chained; verification fails loudly if a line was altered or removed. | `aigis audit verify` |
| Can the logs be tampered with? | Each record is HMAC-signed and hash-chained; verification fails loudly if a line was altered or removed. By default the key sits on the same machine as the agent, so pair this with SIEM forwarding where the person on the machine is in scope — [details](#the-keys-location-bounds-what-the-signature-proves). | `aigis audit verify` |
| What standards does this map to? | A control matrix across ISO/IEC 27001:2022 Annex A, NIST AI RMF, OWASP LLM Top 10, and 経産省 AI 事業者ガイドライン, plus a live OWASP scorecard. | `aigis trust-pack` · `aigis monitor --owasp` |
| What happens on an incident? | The pack ships an incident runbook (NIST SP 800-61 style); weekly digests keep managers in the loop. | `aigis report weekly` |

Expand All @@ -181,6 +185,16 @@ The order matters: Claude Code evaluates its own deny and ask rules regardless o

The Claude Code Team plan exposes no audit-log API, and Enterprise's OpenTelemetry export is metrics-grade — useful for dashboards, but not designed as evidence for an investigation. Aigis hooks produce schema-stable, tamper-evident logs at the machine level regardless of plan, so you have a defensible record even where the platform doesn't provide one.

### The key's location bounds what the signature proves

By default the HMAC key is generated into `.aigis/audit_key` on the same machine as the agent. The signature therefore proves the log was not altered by anyone *without* that file — which is a weaker statement than it first appears, because the developer running the agent has it. Local signing catches an outside editor, not the log's own author.

Three things move that boundary, in increasing order of what they cover:

- Pass an explicit key (`SignedAuditLog(secret_key=...)`) held outside the developer's reach — injected by CI, or read from a secrets manager — instead of using the auto-generated file.
- Restrict access to the key file. Aigis sets POSIX permissions where the OS supports it; on Windows you need to set NTFS ACLs yourself, because `chmod` is not enforced there.
- Forward events off the machine. Once a record is mirrored to Splunk, Datadog, Sentinel, or Elastic ([docs/forwarders.md](docs/forwarders.md)), editing the local copy no longer changes the evidence. This is the control that holds when the person you're auditing is the person on the machine.

### Why an independent OSS layer

The 2025–26 acquisition wave thinned out the independent options: Protect AI was acquired by Palo Alto, Invariant Labs' mcp-scan by Snyk, Lakera by Check Point, promptfoo by OpenAI. Aigis stays independent and Apache-2.0 — you can read every rule and run it in your own CI, instead of depending on a vendor that might be acquired next.
Expand Down
Loading