Skip to main content

workload_spec/
secrets.rs

1//! Pluggable secret resolver for [`crate::SecretRef`] values.
2//!
3//! The trait lives in `workload-spec` so consumers can construct specs and
4//! invoke the resolver without linking yubaba's containerd client. Yubaba
5//! provides the production impl in `crates/yah/yubaba/src/secrets.rs`.
6
7use std::path::PathBuf;
8
9use thiserror::Error;
10
11use crate::SecretRef;
12
13/// Errors returned by [`SecretResolver::resolve`].
14#[derive(Debug, Error)]
15pub enum SecretError {
16    /// The referenced secret file does not exist in the yubaba secret store.
17    #[error("secret not found at {path}")]
18    NotFound { path: PathBuf },
19
20    /// `SecretRef::Cluster` reached a resolver that has no cluster backing —
21    /// e.g. the per-machine `LocalFileResolver`, which cannot decrypt cluster
22    /// secrets. The fleet resolver (yubaba's `ClusterResolver`) handles the
23    /// `Cluster` arm; this error means the wrong resolver was used.
24    #[error("cluster secrets require a cluster-backed resolver")]
25    ClusterNotImplemented,
26
27    /// The referenced cluster secret is not present in the local raft replica
28    /// (never written, or deleted). Fails closed — nothing is served.
29    #[error("cluster secret {name} not found in the local raft replica")]
30    ClusterNotFound { name: String },
31
32    /// Decryption or authentication of a cluster secret failed — a wrong
33    /// node-local KEK, a truncated/tampered record, or a malformed nonce. Fails
34    /// closed; the message carries only the logical name, never key or
35    /// ciphertext bytes.
36    #[error("cluster secret {name} failed to decrypt")]
37    ClusterDecrypt { name: String },
38
39    /// The node-local cluster KEK could not be loaded (missing, unreadable, or
40    /// not exactly 32 bytes). Fails closed; `reason` is a generic diagnostic
41    /// and never contains key material.
42    #[error("cluster KEK unavailable: {reason}")]
43    Kek { reason: String },
44
45    /// I/O error reading the secret file.
46    #[error("I/O error reading {path}: {source}")]
47    Io {
48        path: PathBuf,
49        #[source]
50        source: std::io::Error,
51    },
52}
53
54/// Resolves a [`SecretRef`] to its raw byte content.
55///
56/// The trait is defined here (in `workload-spec`) so callers don't need to
57/// link yubaba. Yubaba's `LocalFileResolver` reads from the per-machine secret
58/// store at `/var/lib/yah/yubaba/secrets/`. Tests use an inline `FakeResolver`.
59pub trait SecretResolver {
60    fn resolve(&self, r: &SecretRef) -> Result<Vec<u8>, SecretError>;
61}