1use async_trait::async_trait;
13use zeroize::Zeroizing;
14
15use basil_proto::{AeadAlgorithm, CiphertextEnvelope, KeyMaterial, KeyType};
16
17use super::pki::PkiClient;
18use super::transit::{TransitClient, transit_aead_type};
19use super::{
20 Backend, BackendError, KeyMetadata, KvValue, NewKey, PublicKey, SignOptions, X509Bundle,
21 X509Svid,
22};
23
24pub struct VaultBackend {
25 transit: TransitClient,
26 pki: PkiClient,
27 token: String,
28}
29
30impl VaultBackend {
31 pub fn new(
34 addr: impl Into<String>,
35 token: impl Into<String>,
36 mount: impl Into<String>,
37 ) -> Result<Self, BackendError> {
38 crate::ensure_crypto_provider();
39 let http = reqwest::Client::builder()
40 .build()
41 .map_err(|e| BackendError::Transport(e.to_string()))?;
42 let addr = addr.into();
43 Ok(Self {
44 transit: TransitClient::new(http.clone(), &addr, &mount.into()),
45 pki: PkiClient::new(http, &addr),
46 token: token.into(),
47 })
48 }
49}
50
51#[async_trait]
52impl Backend for VaultBackend {
53 fn kind(&self) -> &'static str {
54 "vault"
55 }
56
57 async fn new_key(&self, key_type: KeyType) -> Result<NewKey, BackendError> {
58 self.transit.new_key(&self.token, key_type).await
59 }
60
61 async fn create_named_key(
62 &self,
63 key_id: &str,
64 key_type: KeyType,
65 ) -> Result<NewKey, BackendError> {
66 self.transit
67 .create_named_key(&self.token, key_id, key_type)
68 .await
69 }
70
71 async fn create_named_aead(
72 &self,
73 key_id: &str,
74 aead: AeadAlgorithm,
75 ) -> Result<(), BackendError> {
76 self.transit
77 .create_named_aead(&self.token, key_id, transit_aead_type(aead))
78 .await
79 }
80
81 async fn public_key(&self, key_id: &str) -> Result<Vec<u8>, BackendError> {
82 self.transit.read_public_key(&self.token, key_id).await
83 }
84
85 async fn public_key_with_meta(&self, key_id: &str) -> Result<PublicKey, BackendError> {
86 self.transit
87 .read_public_key_with_meta(&self.token, key_id)
88 .await
89 }
90
91 async fn key_metadata(&self, key_id: &str) -> Result<KeyMetadata, BackendError> {
92 self.transit.read_key_metadata(&self.token, key_id).await
93 }
94
95 async fn public_keys(
96 &self,
97 key_id: &str,
98 ) -> Result<std::collections::BTreeMap<u32, Vec<u8>>, BackendError> {
99 self.transit.read_public_keys(&self.token, key_id).await
100 }
101
102 async fn import(
103 &self,
104 key_id: &str,
105 key_type: KeyType,
106 material: &KeyMaterial,
107 ) -> Result<NewKey, BackendError> {
108 self.transit
109 .import(&self.token, key_id, key_type, material)
110 .await
111 }
112
113 async fn sign(&self, key_id: &str, message: &[u8]) -> Result<Vec<u8>, BackendError> {
114 self.transit.sign(&self.token, key_id, message).await
115 }
116
117 async fn sign_with_options(
118 &self,
119 key_id: &str,
120 message: &[u8],
121 options: SignOptions,
122 ) -> Result<Vec<u8>, BackendError> {
123 self.transit
124 .sign_with_options(&self.token, key_id, message, options)
125 .await
126 }
127
128 async fn verify(
129 &self,
130 key_id: &str,
131 message: &[u8],
132 signature: &[u8],
133 ) -> Result<bool, BackendError> {
134 self.transit
135 .verify(&self.token, key_id, message, signature)
136 .await
137 }
138
139 async fn verify_with_options(
140 &self,
141 key_id: &str,
142 message: &[u8],
143 signature: &[u8],
144 options: SignOptions,
145 ) -> Result<bool, BackendError> {
146 self.transit
147 .verify_with_options(&self.token, key_id, message, signature, options)
148 .await
149 }
150
151 async fn encrypt(
152 &self,
153 key_id: &str,
154 algorithm: AeadAlgorithm,
155 plaintext: &[u8],
156 aad: Option<&[u8]>,
157 ) -> Result<CiphertextEnvelope, BackendError> {
158 self.transit
159 .encrypt(&self.token, key_id, algorithm, plaintext, aad)
160 .await
161 }
162
163 async fn decrypt(
164 &self,
165 key_id: &str,
166 envelope: &CiphertextEnvelope,
167 aad: Option<&[u8]>,
168 ) -> Result<Vec<u8>, BackendError> {
169 self.transit
170 .decrypt(&self.token, key_id, envelope, aad)
171 .await
172 }
173
174 async fn rotate(&self, key_id: &str) -> Result<u32, BackendError> {
175 self.transit.rotate(&self.token, key_id).await
176 }
177
178 async fn kv_get(&self, key_id: &str, version: Option<u32>) -> Result<KvValue, BackendError> {
179 self.transit.kv_get(&self.token, key_id, version).await
180 }
181
182 async fn kv_get_secret(
183 &self,
184 key_id: &str,
185 version: Option<u32>,
186 ) -> Result<Zeroizing<Vec<u8>>, BackendError> {
187 self.transit
188 .kv_get_secret(&self.token, key_id, version)
189 .await
190 }
191
192 async fn kv_put(&self, key_id: &str, value: &[u8]) -> Result<u32, BackendError> {
193 self.transit.kv_put(&self.token, key_id, value).await
194 }
195
196 async fn configure_versions(
197 &self,
198 key_id: &str,
199 min_decryption_version: Option<u32>,
200 min_available_version: Option<u32>,
201 ) -> Result<(), BackendError> {
202 self.transit
203 .configure_versions(
204 &self.token,
205 key_id,
206 min_decryption_version,
207 min_available_version,
208 )
209 .await
210 }
211
212 async fn issue_x509_svid(
213 &self,
214 key_id: &str,
215 spiffe_id: &str,
216 ttl_seconds: u64,
217 ) -> Result<X509Svid, BackendError> {
218 self.pki
219 .issue_x509_svid(&self.token, key_id, spiffe_id, ttl_seconds)
220 .await
221 }
222
223 async fn issue_x509_cert(
224 &self,
225 key_id: &str,
226 request: &super::X509CertRequest,
227 ) -> Result<X509Svid, BackendError> {
228 self.pki.issue_x509_cert(&self.token, key_id, request).await
229 }
230
231 async fn x509_bundle(&self, key_id: &str) -> Result<X509Bundle, BackendError> {
232 self.pki.x509_bundle(&self.token, key_id).await
233 }
234}