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