2026-04-15 12:06:28 +00:00
|
|
|
# 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 si `LookupEnv` est fourni
|
|
|
|
|
- `kwallet-only` : impose KWallet et retourne une erreur explicite si KWallet n'est pas disponible
|
|
|
|
|
- `keyring-any` : impose l'utilisation d'un backend keyring disponible
|
|
|
|
|
- `env-only` : lecture seule depuis les variables d'environnement
|
2026-04-20 06:30:35 +00:00
|
|
|
- `bitwarden-cli` : utilise le CLI Bitwarden (`bw`) comme backend de vault
|
2026-04-15 12:06:28 +00:00
|
|
|
|
|
|
|
|
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) :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
store, err := secretstore.OpenFromManifest(secretstore.OpenFromManifestOptions{
|
|
|
|
|
ServiceName: "my-mcp",
|
|
|
|
|
LookupEnv: os.LookupEnv,
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Exemple bas niveau :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
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 :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
store, err := secretstore.Open(secretstore.Options{
|
|
|
|
|
ServiceName: "email-mcp",
|
|
|
|
|
BackendPolicy: secretstore.BackendKWalletOnly,
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-20 06:30:35 +00:00
|
|
|
Pour imposer Bitwarden via son CLI :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
store, err := secretstore.Open(secretstore.Options{
|
|
|
|
|
ServiceName: "email-mcp",
|
|
|
|
|
BackendPolicy: secretstore.BackendBitwardenCLI,
|
|
|
|
|
// Optionnel si `bw` n'est pas dans le PATH :
|
|
|
|
|
// BitwardenCommand: "/usr/local/bin/bw",
|
|
|
|
|
})
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-20 07:39:05 +00:00
|
|
|
Pour vérifier explicitement que Bitwarden est prêt (login + unlock + `BW_SESSION`) :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-15 12:06:28 +00:00
|
|
|
Pour stocker un secret structuré en JSON :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
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
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-20 07:39:05 +00:00
|
|
|
Pour écrire puis confirmer immédiatement une relecture :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
if err := secretstore.SetSecretVerified(store, "api-token", "My MCP API token", token); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
Pour connaître le backend effectif utilisé :
|
|
|
|
|
|
|
|
|
|
```go
|
|
|
|
|
effective := secretstore.EffectiveBackendPolicy(store)
|
|
|
|
|
fmt.Println("backend effectif:", effective) // bitwarden-cli, env-only, keyring-any...
|
|
|
|
|
```
|
|
|
|
|
|
2026-04-15 12:06:28 +00:00
|
|
|
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`.
|