Aller au contenu

Démarrage rapide

Le chemin critique s’exécute de bout en bout depuis un clone frais : un agent parle MCP à la passerelle, la politique décide, le journal est scellé, et l’auditeur vérifie hors ligne.

Fenêtre de terminal
git clone https://github.com/obsign/obsign
cd obsign
cargo build --workspace
cargo run -p obsign-policy --example mkbundle -- /tmp/demo
cargo run -p obsign-proxy --example mint_demo_token -- /tmp/demo 1800 user
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"delete_production_db","arguments":{"database":"customers"}}}' \
'{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"ticket_update","arguments":{"ticket":"T-8821"}}}' \
'{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"send_message","arguments":{"channel":"#support","text":"T-8821 updated"}}}' \
'{"jsonrpc":"2.0","id":5,"method":"tools/call","params":{"name":"send_message","arguments":{"channel":"#all-hands","text":"T-8821 updated"}}}' \
| ./target/debug/obsign-proxy \
--policy /tmp/demo/policy-bundle.json \
--trusted-keys /tmp/demo/trusted-keys.json \
--identity-bundle /tmp/demo/identity-bundle.json \
--token-file /tmp/demo/token.jwt \
--wal /tmp/demo/wal --chain-id demo --env prod \
-- ./target/debug/mock-mcp-server

Ce qui se produit :

[obsign] identity PROVEN — u:marie.dupont via https://sso.acme.fr/realms/corp — expires in 1756 s
[obsign] REFUSED delete_production_db: forbidden by an explicit rule
[obsign] tools/list: 2 hidden — delete_production_db, exfiltrate_secrets
[server] EXECUTING ticket_update
[server] EXECUTING send_message
[obsign] REFUSED send_message: forbidden by an explicit rule

Trois points méritent attention :

  • Le serveur MCP n’a jamais vu l’appel destructeur. Le refus a lieu à la passerelle, avant la transmission.
  • exfiltrate_secrets est refusé lui aussi. Le serveur l’annonce, mais le catalogue signé ne le décrit pas, et le catalogue fait foi.
  • send_message s’est exécuté exactement une fois. Même outil, deux verdicts. La différence est un argument. La règle lit context.args.channel :
@id("support_channel_only")
forbid (principal, action == Action::"tool_call", resource == Tool::"send_message")
when { context.args.channel != "#support" };

Le WAL sous /tmp/demo/wal est la seule sortie de la passerelle, qui ne détient aucune clé de signature. Le scellement est le travail du ledger, avec une clé que la passerelle ne voit jamais :

Fenêtre de terminal
openssl rand -hex 32 > /tmp/demo/seal-seed.hex
./target/debug/obsign-ledger seal \
--wal /tmp/demo/wal --chain-id demo \
--store /tmp/demo/ledger \
--key /tmp/demo/seal-seed.hex --key-id seal-prod
./target/debug/obsign-ledger export \
--wal /tmp/demo/wal --chain-id demo \
--store /tmp/demo/ledger --out /tmp/demo/evidence.json

(Le fichier de clé hexadécimale est de qualité développement par construction ; le scellement en production passe par un HSM. Voir Scellement & le ledger.)

Fenêtre de terminal
./target/debug/obsign verify /tmp/demo/evidence.json \
--trusted-keys /tmp/demo/ledger/keys.json
# exit 0 — proven
sed -i '' 's/"outcome": "deny"/"outcome": "allow"/' /tmp/demo/evidence.json
./target/debug/obsign verify /tmp/demo/evidence.json \
--trusted-keys /tmp/demo/ledger/keys.json
# exit 1 — tampered

Les codes de sortie et ce qu’ils signifient : Vérifier une preuve.

Fenêtre de terminal
docker compose up -d gateway console
docker compose run --rm demo # the demo above, sealed and verified: exit 0