mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-21 14:08:11 +02:00
API interne pour la façade Rust : clé de pilotage à la demande
Lot 2 de la migration : la façade va authentifier elle-même ses routes /api/*. La clé de pilotage vit dans la base bbolt, verrouillée par ce process ; la façade la demande donc à GET /internal/v1/auth, à chaque requête — un changement de clé prend effet tout de suite, comme avant. La réponse contient un secret, d'où trois verrous : route branchée uniquement sur l'écoute TCP directe (le tunnel du relais sert le mux nu), jeton tiré au hasard par la façade à chaque démarrage et exigé en temps constant, 404 sans rien révéler sinon. Base illisible : 503, la façade fermera l'accès plutôt que de l'ouvrir. Spec du lot 2 jointe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4b859c4eb6
commit
a99d988e70
4 files changed
+233
-1
No files matched your search
@@ -0,0 +1,81 @@
|
||||
package loki
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// API interne entre la façade Rust (rust/loki-rs) et ce serveur.
|
||||
//
|
||||
// La façade reprend des routes une à une ; pour authentifier celles qu'elle
|
||||
// sert elle-même, elle doit connaître la clé de pilotage, qui vit dans la base
|
||||
// bbolt — verrouillée en exclusif par ce process. Elle la demande donc ici, à
|
||||
// chaque requête (même règle que requireWebAuth : un changement de clé prend
|
||||
// effet immédiatement).
|
||||
//
|
||||
// Trois verrous, parce que la réponse contient un secret :
|
||||
// - la route n'existe que sur l'écoute TCP directe (withInternalAPI enveloppe
|
||||
// le mux dans cmdWeb) : le tunnel du relais sert le mux nu et ne la voit
|
||||
// jamais ;
|
||||
// - elle exige le jeton que la façade tire au hasard à chaque démarrage et
|
||||
// transmet par l'environnement (LOKI_INTERNAL_TOKEN) ;
|
||||
// - sans jeton, jeton trop court ou faux : 404, rien ne trahit la route.
|
||||
|
||||
const (
|
||||
internalTokenEnv = "LOKI_INTERNAL_TOKEN"
|
||||
internalTokenHeader = "X-Loki-Internal"
|
||||
internalPrefix = "/internal/"
|
||||
// Un jeton plus court qu'un secret de 128 bits désactive l'API interne :
|
||||
// mieux vaut une façade qui ferme l'accès qu'une route devinable.
|
||||
internalTokenMinLen = 32
|
||||
)
|
||||
|
||||
func internalToken() string {
|
||||
t := strings.TrimSpace(os.Getenv(internalTokenEnv))
|
||||
if len(t) < internalTokenMinLen {
|
||||
return ""
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// withInternalAPI sert /internal/* et passe tout le reste à next.
|
||||
func withInternalAPI(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasPrefix(r.URL.Path, internalPrefix) {
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
tok := internalToken()
|
||||
got := r.Header.Get(internalTokenHeader)
|
||||
if tok == "" || subtle.ConstantTimeCompare([]byte(got), []byte(tok)) != 1 {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
switch r.URL.Path {
|
||||
case "/internal/v1/auth":
|
||||
handleInternalAuth(w, r)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// handleInternalAuth : de quoi authentifier une requête de pilotage côté Rust.
|
||||
// Base illisible → 503 : la façade ferme alors l'accès, elle n'ouvre jamais
|
||||
// sur une panne d'E/S (cf. readWebKeyErr).
|
||||
func handleInternalAuth(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
w.Header().Set("Allow", http.MethodGet)
|
||||
sendJSON(w, http.StatusMethodNotAllowed, map[string]any{"error": "GET attendu"})
|
||||
return
|
||||
}
|
||||
key, err := readWebKeyErr()
|
||||
if err != nil {
|
||||
sendJSON(w, http.StatusServiceUnavailable, map[string]any{"error": "configuration illisible"})
|
||||
return
|
||||
}
|
||||
w.Header().Set("Cache-Control", "no-store")
|
||||
sendJSON(w, http.StatusOK, map[string]any{"web_key": key, "version": Version})
|
||||
}
|
||||
Reference in new issue
Block a user