1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use async_trait::async_trait;
use derive_more::Deref;
use error_code::{self, ErrorCode, ErrorCodeExt};
use std::fmt::Debug;
use std::path::Path;
use tikv_util::stream::RetryError;
use tikv_util::{error, info};
#[cfg(feature = "cloud-aws")]
use aws::{AwsKms, STORAGE_VENDOR_NAME_AWS};
#[cfg(feature = "cloud-aws")]
use cloud::kms::Config as CloudConfig;
use cloud::kms::{EncryptedKey as CloudEncryptedKey, KmsProvider as CloudKmsProvider};
use cloud::Error as CloudError;
#[cfg(feature = "cloud-aws")]
pub use encryption::KmsBackend;
pub use encryption::{
encryption_method_from_db_encryption_method, Backend, DataKeyManager, DataKeyManagerArgs,
DecrypterReader, EncryptionConfig, Error, FileConfig, Iv, KmsConfig, MasterKeyConfig, Result,
};
use encryption::{
DataKeyPair, EncryptedKey, FileBackend, KmsProvider, PlainKey, PlaintextBackend,
RetryCodedError,
};
use tikv_util::box_err;
pub fn data_key_manager_from_config(
config: &EncryptionConfig,
dict_path: &str,
) -> Result<Option<DataKeyManager>> {
let master_key = create_backend(&config.master_key).map_err(|e| {
error!("failed to access master key, {}", e);
e
})?;
let args = DataKeyManagerArgs::from_encryption_config(dict_path, config);
let previous_master_key_conf = config.previous_master_key.clone();
let previous_master_key = Box::new(move || create_backend(&previous_master_key_conf));
DataKeyManager::new(master_key, previous_master_key, args)
}
pub fn create_backend(config: &MasterKeyConfig) -> Result<Box<dyn Backend>> {
let result = create_backend_inner(config);
if let Err(e) = result {
error!("failed to access master key, {}", e);
return Err(e);
};
result
}
fn cloud_convert_error(msg: String) -> Box<dyn FnOnce(CloudError) -> CloudConvertError> {
Box::new(|err: CloudError| CloudConvertError(err, msg))
}
pub fn create_cloud_backend(config: &KmsConfig) -> Result<Box<dyn Backend>> {
info!("Encryption init cloud backend";
"region" => &config.region,
"endpoint" => &config.endpoint,
"key_id" => &config.key_id,
"vendor" => &config.vendor,
);
match config.vendor.as_str() {
#[cfg(feature = "cloud-aws")]
STORAGE_VENDOR_NAME_AWS | "" => {
let conf = CloudConfig::from_proto(config.clone().into_proto())
.map_err(cloud_convert_error("aws from proto".to_owned()))?;
let kms_provider = CloudKms(Box::new(
AwsKms::new(conf).map_err(cloud_convert_error("new AWS KMS".to_owned()))?,
));
Ok(Box::new(KmsBackend::new(Box::new(kms_provider))?) as Box<dyn Backend>)
}
provider => Err(Error::Other(box_err!("provider not found {}", provider))),
}
}
fn create_backend_inner(config: &MasterKeyConfig) -> Result<Box<dyn Backend>> {
Ok(match config {
MasterKeyConfig::Plaintext => Box::new(PlaintextBackend {}) as _,
MasterKeyConfig::File { config } => {
Box::new(FileBackend::new(Path::new(&config.path))?) as _
}
MasterKeyConfig::Kms { config } => return create_cloud_backend(config),
})
}
#[derive(Debug, Deref)]
struct CloudKms(Box<dyn CloudKmsProvider>);
#[async_trait]
impl KmsProvider for CloudKms {
async fn generate_data_key(&self) -> Result<DataKeyPair> {
let cdk = (**self)
.generate_data_key()
.await
.map_err(cloud_convert_error(format!(
"{} generate data key API",
self.name()
)))?;
Ok(DataKeyPair {
plaintext: PlainKey::new(cdk.plaintext.to_vec())?,
encrypted: EncryptedKey::new(cdk.encrypted.to_vec())?,
})
}
async fn decrypt_data_key(&self, data_key: &EncryptedKey) -> Result<Vec<u8>> {
let key = CloudEncryptedKey::new((*data_key).to_vec()).map_err(cloud_convert_error(
format!("{} data key init for decrypt", self.name()),
))?;
Ok((**self)
.decrypt_data_key(&key)
.await
.map_err(cloud_convert_error(format!(
"{} decrypt data key API",
self.name()
)))?)
}
fn name(&self) -> &str {
(**self).name()
}
}
#[derive(Debug)]
pub struct CloudConvertError(CloudError, String);
impl RetryCodedError for CloudConvertError {}
impl std::fmt::Display for CloudConvertError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_fmt(format_args!("{} {}", &self.0, &self.1))
}
}
impl std::convert::From<CloudConvertError> for Error {
fn from(err: CloudConvertError) -> Error {
Error::RetryCodedError(Box::new(err) as Box<dyn RetryCodedError>)
}
}
impl RetryError for CloudConvertError {
fn is_retryable(&self) -> bool {
self.0.is_retryable()
}
}
impl ErrorCodeExt for CloudConvertError {
fn error_code(&self) -> ErrorCode {
self.0.error_code()
}
}