jsonrpc: optional TLS termination (HTTP/2)
[jsonrpc].tls = { cert, key } makes the endpoint terminate TLS itself,
which also enables HTTP/2 (ALPN), so traffic is encrypted right up to
fedserv — for when it runs on a different host from the site, or the
browser's TLS should reach it directly. Absent = plain HTTP for a
reverse-proxy front. Reuses the same cert/key shape as [grpc]; a crypto
provider is pinned before building the config (the tree carries more than
one). Verified the TLS config builds against a real cert without a
provider panic.
This commit is contained in:
parent
92417e7a7c
commit
540d2f39d1
4 changed files with 75 additions and 7 deletions
|
|
@ -105,6 +105,10 @@ pub struct JsonRpc {
|
|||
// ["https://tchatou.fr", "https://swaygo.fr"]. Empty = no browser access.
|
||||
#[serde(default)]
|
||||
pub origins: Vec<String>,
|
||||
// Terminate TLS here (enabling HTTP/2). Absent = plain HTTP, for when a
|
||||
// reverse proxy does TLS. Reuses the same cert/key shape as [grpc].
|
||||
#[serde(default)]
|
||||
pub tls: Option<ServerTls>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
|
|
|
|||
|
|
@ -38,18 +38,39 @@ pub async fn run(engine: Shared, cfg: JsonRpcCfg) {
|
|||
if cfg.token.is_empty() {
|
||||
return tracing::error!("jsonrpc token is empty; refusing to start an unauthenticated stats endpoint");
|
||||
}
|
||||
let tls = cfg.tls.clone();
|
||||
let state = AppState { engine, token: cfg.token, origins: Arc::new(cfg.origins) };
|
||||
let app = Router::new()
|
||||
.route("/", post(handle).options(preflight))
|
||||
.layer(DefaultBodyLimit::max(64 * 1024))
|
||||
.with_state(state);
|
||||
let listener = match tokio::net::TcpListener::bind(addr).await {
|
||||
Ok(l) => l,
|
||||
Err(e) => return tracing::error!(%e, %addr, "jsonrpc bind failed"),
|
||||
};
|
||||
tracing::info!(%addr, "jsonrpc stats API listening");
|
||||
if let Err(e) = axum::serve(listener, app).await {
|
||||
tracing::error!(%e, "jsonrpc server exited");
|
||||
|
||||
match tls {
|
||||
// TLS terminated here → HTTP/2 (ALPN) plus HTTP/1.1, encrypted to fedserv.
|
||||
Some(t) => {
|
||||
// The dependency tree carries more than one rustls crypto provider, so
|
||||
// pin one before building any TLS config (ignored if already set).
|
||||
let _ = tokio_rustls::rustls::crypto::aws_lc_rs::default_provider().install_default();
|
||||
let config = match axum_server::tls_rustls::RustlsConfig::from_pem_file(&t.cert, &t.key).await {
|
||||
Ok(c) => c,
|
||||
Err(e) => return tracing::error!(%e, "jsonrpc TLS cert/key unreadable"),
|
||||
};
|
||||
tracing::info!(%addr, "jsonrpc stats API listening (TLS, HTTP/2)");
|
||||
if let Err(e) = axum_server::bind_rustls(addr, config).serve(app.into_make_service()).await {
|
||||
tracing::error!(%e, "jsonrpc server exited");
|
||||
}
|
||||
}
|
||||
// Plain HTTP, for when a reverse proxy terminates TLS/HTTP-2/HTTP-3.
|
||||
None => {
|
||||
let listener = match tokio::net::TcpListener::bind(addr).await {
|
||||
Ok(l) => l,
|
||||
Err(e) => return tracing::error!(%e, %addr, "jsonrpc bind failed"),
|
||||
};
|
||||
tracing::info!(%addr, "jsonrpc stats API listening");
|
||||
if let Err(e) = axum::serve(listener, app).await {
|
||||
tracing::error!(%e, "jsonrpc server exited");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue