6.8 KiB
Secrets
Le package secretstore supporte plusieurs politiques de backend :
auto: comportement par défaut, utilise un backend keyring disponible et peut retomber sur l'environnement siLookupEnvest fournikwallet-only: impose KWallet et retourne une erreur explicite si KWallet n'est pas disponiblekeyring-any: impose l'utilisation d'un backend keyring disponibleenv-only: lecture seule depuis les variables d'environnementbitwarden-cli: utilise le CLI Bitwarden (bw) comme backend de vault
Backends keyring typiques :
- macOS : Keychain
- Linux : Secret Service ou KWallet selon l'environnement
- Windows : Credential Manager
Ouverture recommandée depuis la policy du manifeste runtime (mcp.toml résolu près de l'exécutable) :
store, err := secretstore.OpenFromManifest(secretstore.OpenFromManifestOptions{
ServiceName: "my-mcp",
LookupEnv: os.LookupEnv,
})
if err != nil {
return err
}
Exemple bas niveau :
store, err := secretstore.Open(secretstore.Options{
ServiceName: "my-mcp",
BackendPolicy: secretstore.BackendAuto,
})
if err != nil {
return err
}
if err := store.SetSecret("api-token", "My MCP API token", token); err != nil {
return err
}
token, err = store.GetSecret("api-token")
switch {
case err == nil:
// secret found
case errors.Is(err, secretstore.ErrNotFound):
// first run
default:
return err
}
Pour imposer KWallet sur Linux :
store, err := secretstore.Open(secretstore.Options{
ServiceName: "my-mcp",
BackendPolicy: secretstore.BackendKWalletOnly,
})
Pour imposer Bitwarden via son CLI :
store, err := secretstore.Open(secretstore.Options{
ServiceName: "my-mcp",
BackendPolicy: secretstore.BackendBitwardenCLI,
// Optionnel si `bw` n'est pas dans le PATH :
// BitwardenCommand: "/usr/local/bin/bw",
})
Cache Bitwarden
Le backend bitwarden-cli met en cache les lectures de secrets par défaut.
Le cache mémoire évite les appels répétés au CLI dans un même process. Le cache
disque est chiffré avec une clé dérivée de BW_SESSION via HKDF-SHA256 et
AES-GCM.
TTL par défaut : 10 minutes.
Pour désactiver le cache dans mcp.toml :
[secret_store]
backend_policy = "bitwarden-cli"
bitwarden_cache = false
Pour le désactiver sans modifier le manifeste :
MCP_FRAMEWORK_BITWARDEN_CACHE=0
Le fichier de cache et le binaire installé ne suffisent pas à déchiffrer les
secrets. Si BW_SESSION change ou disparaît, les entrées disque existantes
deviennent inutilisables. Cette protection ne couvre pas un attaquant qui peut
lire l'environnement ou la mémoire du process pendant l'exécution.
Pour vérifier explicitement que Bitwarden est prêt (login + unlock + BW_SESSION) :
if err := secretstore.EnsureBitwardenReady(secretstore.Options{
BitwardenCommand: "bw",
LookupEnv: os.LookupEnv,
}); err != nil {
switch {
case errors.Is(err, secretstore.ErrBWNotLoggedIn):
// guider vers `bw login`
case errors.Is(err, secretstore.ErrBWLocked):
// guider vers `bw unlock --raw` puis export BW_SESSION
default:
// indisponibilité CLI/réseau
}
return err
}
Pour lancer un flux interactif bw login / bw unlock --raw, récupérer BW_SESSION
et le persister localement (fichier 0600 sous le répertoire de config utilisateur) :
session, err := secretstore.LoginBitwarden(secretstore.BitwardenLoginOptions{
ServiceName: "my-mcp",
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
})
if err != nil {
return err
}
fmt.Println("session chargée:", len(session) > 0)
Pour réinjecter automatiquement une session persistée dans l'environnement courant :
loaded, err := secretstore.EnsureBitwardenSessionEnv(secretstore.BitwardenSessionOptions{
ServiceName: "my-mcp",
})
if err != nil {
return err
}
fmt.Println("session restaurée depuis disque:", loaded)
Pour stocker un secret structuré en JSON :
type Credentials struct {
Host string `json:"host"`
Username string `json:"username"`
Password string `json:"password"`
}
err = secretstore.SetJSON(store, "imap-credentials", "IMAP credentials", Credentials{
Host: "imap.example.com",
Username: "alice",
Password: token,
})
if err != nil {
return err
}
creds, err := secretstore.GetJSON[Credentials](store, "imap-credentials")
if err != nil {
return err
}
_ = creds
Pour écrire puis confirmer immédiatement une relecture :
if err := secretstore.SetSecretVerified(store, "api-token", "My MCP API token", token); err != nil {
return err
}
Pour connaître le backend effectif utilisé :
effective := secretstore.EffectiveBackendPolicy(store)
fmt.Println("backend effectif:", effective) // bitwarden-cli, env-only, keyring-any...
Pour obtenir en un seul appel une description runtime légère (source manifeste, policy déclarée/effective, backend affiché) :
desc, err := secretstore.DescribeRuntime(secretstore.DescribeRuntimeOptions{
ServiceName: "my-mcp",
LookupEnv: os.LookupEnv,
})
if err != nil {
return err
}
fmt.Println(secretstore.FormatBackendStatus(desc))
// declared=... effective=... display=... ready=... source=...
DescribeRuntime ne contacte pas Bitwarden par défaut. Pour vérifier réellement
la disponibilité du backend, utiliser le préflight :
report, err := secretstore.PreflightFromManifest(secretstore.PreflightOptions{
ServiceName: "my-mcp",
LookupEnv: os.LookupEnv,
})
if err != nil {
return err
}
fmt.Println(report.Status) // ready | fail
fmt.Println(report.Summary) // message court
fmt.Println(report.Remediation) // action recommandée
Debug Bitwarden en 60 secondes
Tu peux activer les traces d'appels Bitwarden avec le flag CLI global --debug
(via bootstrap) ou en exportant MCP_FRAMEWORK_BITWARDEN_DEBUG=1.
Les commandes bw exécutées seront affichées (avec redaction des payloads sensibles).
- Vérifier l'état de session :
bw status
- Déverrouiller le vault et exporter
BW_SESSION(ou utiliserLoginBitwarden) :
- Bash/Zsh :
export BW_SESSION="$(bw unlock --raw)"
- Fish :
set -x BW_SESSION (bw unlock --raw)
- PowerShell :
$env:BW_SESSION = (bw unlock --raw)
- Vérifier lecture/écriture rapide :
if err := store.SetSecret("debug-token", "Debug token", "ok"); err != nil {
return err
}
_, err := store.GetSecret("debug-token")
return err
- Interpréter les erreurs typées :
secretstore.ErrBWNotLoggedIn:bw loginrequis.secretstore.ErrBWLocked: vault verrouillé ouBW_SESSIONabsent.secretstore.ErrBWUnavailable: CLI/réseau indisponible.secretstore.ErrBackendUnavailable: policy non satisfiable dans le contexte courant.
En mode env-only, GetSecret("API_TOKEN") lit la variable d'environnement API_TOKEN.
Les opérations d'écriture et de suppression retournent secretstore.ErrReadOnly.