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