Skip to content

Commit 12875e6

Browse files
mayastor-borsJohn Zakrzewski
andcommitted
chore(bors): merge pull request #927
927: Feature: Configuring rest components for TLS r=tiagolobocastro a=Johnaius This PR configures components using rest protocols to speak tls. It is dependent on [this PR in extensions repo](openebs/mayastor-extensions#622). ### Rest-api Clients - Modified certificate loading to use pkcs8_private_keys instead of rsa_private_keys. This was a change I made to get the generated certificates to work, they were apparently created in pkcs8 format, not rsa - I attempted to convert them with no luck, and found the pkcs8_private_keys in the [rustl-pemfile crate](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/)... ### Csi-controller and Diskpool operator: - Added support for TLS configuration based on CA certificate path. - if certs are provided, use https, if not use http. - error handling for HTTPS connections without a certificate etc Co-authored-by: John Zakrzewski <[email protected]>
2 parents 27d24e5 + 832ea4e commit 12875e6

File tree

7 files changed

+214
-33
lines changed

7 files changed

+214
-33
lines changed

control-plane/csi-driver/src/bin/controller/client.rs

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,49 @@ impl RestApiClient {
123123
let url = clients::tower::Url::parse(endpoint)
124124
.map_err(|error| anyhow!("Invalid API endpoint URL {}: {:?}", endpoint, error))?;
125125
let concurrency_limit = cfg.create_volume_limit() * 2;
126-
let tower = clients::tower::Configuration::builder()
127-
.with_timeout(cfg.io_timeout())
128-
.with_concurrency_limit(Some(concurrency_limit))
129-
.build_url(url)
130-
.map_err(|error| {
131-
anyhow::anyhow!(
132-
"Failed to create openapi configuration, Error: '{:?}'",
133-
error
134-
)
135-
})?;
126+
let ca_certificate_path = cfg.ca_certificate_path();
127+
let cert = match ca_certificate_path {
128+
Some(path) => {
129+
let cert = std::fs::read(path).map_err(|error| {
130+
anyhow::anyhow!(
131+
"Failed to create openapi configuration at path {}, Error: '{:?}'",
132+
path.display(),
133+
error
134+
)
135+
})?;
136+
Some(cert)
137+
}
138+
None => None,
139+
};
140+
let tower = match (url.scheme(), cert) {
141+
("https", Some(cert)) => clients::tower::Configuration::builder()
142+
.with_timeout(Some(cfg.io_timeout()))
143+
.with_concurrency_limit(Some(concurrency_limit))
144+
.with_certificate(cert.as_slice())
145+
.build_url(url)
146+
.map_err(|error| {
147+
anyhow::anyhow!(
148+
"Failed to create openapi configuration, Error: '{:?}'",
149+
error
150+
)
151+
})?,
152+
("https", None) => {
153+
anyhow::bail!("HTTPS endpoint requires a CA certificate path");
154+
}
155+
(_, Some(_path)) => {
156+
anyhow::bail!("CA certificate path is only supported for HTTPS endpoints");
157+
}
158+
_ => clients::tower::Configuration::builder()
159+
.with_timeout(Some(cfg.io_timeout()))
160+
.with_concurrency_limit(Some(concurrency_limit))
161+
.build_url(url)
162+
.map_err(|error| {
163+
anyhow::anyhow!(
164+
"Failed to create openapi configuration, Error: '{:?}'",
165+
error
166+
)
167+
})?,
168+
};
136169

137170
REST_CLIENT.get_or_init(|| Self {
138171
rest_client: clients::tower::ApiClient::new(tower.clone()),

control-plane/csi-driver/src/bin/controller/config.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use anyhow::Context;
22
use clap::ArgMatches;
33
use once_cell::sync::OnceCell;
4-
use std::{collections::HashMap, time::Duration};
4+
use std::{
5+
collections::HashMap,
6+
path::{Path, PathBuf},
7+
time::Duration,
8+
};
59

610
static CONFIG: OnceCell<CsiControllerConfig> = OnceCell::new();
711

@@ -17,6 +21,8 @@ pub(crate) struct CsiControllerConfig {
1721
create_volume_limit: usize,
1822
/// Force unstage volume.
1923
force_unstage_volume: bool,
24+
/// Path to the CA certificate file.
25+
ca_certificate_path: Option<PathBuf>,
2026
}
2127

2228
impl CsiControllerConfig {
@@ -50,14 +56,17 @@ impl CsiControllerConfig {
5056
tracing::warn!(
5157
"Force unstage volume is disabled, can trigger potential data corruption!"
5258
);
53-
}
59+
};
60+
61+
let ca_certificate_path: Option<&PathBuf> = args.get_one::<PathBuf>("tls-client-ca-path");
5462

5563
CONFIG.get_or_init(|| Self {
5664
rest_endpoint: rest_endpoint.into(),
5765
io_timeout: io_timeout.into(),
5866
node_selector,
5967
create_volume_limit,
6068
force_unstage_volume,
69+
ca_certificate_path: ca_certificate_path.cloned(),
6170
});
6271
Ok(())
6372
}
@@ -92,4 +101,9 @@ impl CsiControllerConfig {
92101
pub(crate) fn force_unstage_volume(&self) -> bool {
93102
self.force_unstage_volume
94103
}
104+
105+
/// Path to the CA certificate file.
106+
pub(crate) fn ca_certificate_path(&self) -> Option<&Path> {
107+
self.ca_certificate_path.as_deref()
108+
}
95109
}

control-plane/csi-driver/src/bin/controller/main.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ async fn main() -> anyhow::Result<()> {
131131
.value_parser(clap::value_parser!(bool))
132132
.help("Enable force unstage volume feature")
133133
)
134+
.arg(
135+
Arg::new("tls-client-ca-path")
136+
.long("tls-client-ca-path")
137+
.help("path to the CA certificate file")
138+
)
134139
.get_matches();
135140

136141
utils::print_package_info!();

control-plane/csi-driver/src/bin/node/client.rs

Lines changed: 89 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use stor_port::types::v0::openapi::{
66
};
77

88
use anyhow::anyhow;
9-
use std::{collections::HashMap, sync::Arc, time::Duration};
9+
use std::{collections::HashMap, path::PathBuf, sync::Arc, time::Duration};
1010
use stor_port::types::v0::openapi::{
1111
apis::{
1212
app_nodes_api::tower::client::direct::AppNodes,
@@ -107,6 +107,7 @@ impl AppNodesClientWrapper {
107107
/// Initialize AppNodes API client instance.
108108
pub(crate) fn initialize(
109109
endpoint: Option<&String>,
110+
ca_certificate_path: Option<&PathBuf>,
110111
) -> anyhow::Result<Option<AppNodesClientWrapper>> {
111112
const REST_TIMEOUT: Duration = Duration::from_secs(5);
112113

@@ -117,12 +118,49 @@ impl AppNodesClientWrapper {
117118
let url = clients::tower::Url::parse(endpoint)
118119
.map_err(|error| anyhow!("Invalid API endpoint URL {endpoint}: {error:?}"))?;
119120

120-
let tower = clients::tower::Configuration::builder()
121-
.with_timeout(REST_TIMEOUT)
122-
.build_url(url)
123-
.map_err(|error| {
124-
anyhow::anyhow!("Failed to create openapi configuration, Error: '{error:?}'")
125-
})?;
121+
let cert = match ca_certificate_path {
122+
Some(path) => {
123+
let cert = std::fs::read(path).map_err(|error| {
124+
anyhow::anyhow!(
125+
"Failed to create openapi configuration at path {}, Error: '{:?}'",
126+
path.display(),
127+
error
128+
)
129+
})?;
130+
Some(cert)
131+
}
132+
None => None,
133+
};
134+
135+
let tower = match (url.scheme(), cert) {
136+
("https", Some(cert)) => clients::tower::Configuration::builder()
137+
.with_timeout(REST_TIMEOUT)
138+
.with_concurrency_limit(Some(10))
139+
.with_certificate(&cert)
140+
.build_url(url)
141+
.map_err(|error| {
142+
anyhow::anyhow!(
143+
"Failed to create openapi configuration***, Error: '{:?}'",
144+
error
145+
)
146+
})?,
147+
("https", None) => {
148+
anyhow::bail!("HTTPS endpoint requires a CA certificate path");
149+
}
150+
(_, Some(_path)) => {
151+
anyhow::bail!("CA certificate path is only supported for HTTPS endpoints");
152+
}
153+
_ => clients::tower::Configuration::builder()
154+
.with_timeout(REST_TIMEOUT)
155+
.with_concurrency_limit(Some(10))
156+
.build_url(url)
157+
.map_err(|error| {
158+
anyhow::anyhow!(
159+
"Failed to create openapi configuration, Error???: '{:?}'",
160+
error
161+
)
162+
})?,
163+
};
126164

127165
info!(
128166
"API client is initialized with endpoint {endpoint}, request timeout = {REST_TIMEOUT:?}"
@@ -169,20 +207,56 @@ pub(crate) struct VolumesClientWrapper {
169207

170208
impl VolumesClientWrapper {
171209
/// Initialize VolumesClientWrapper instance.
172-
pub(crate) fn new(endpoint: &str) -> anyhow::Result<Self> {
210+
pub(crate) fn new(
211+
endpoint: &str,
212+
ca_certificate_path: Option<PathBuf>,
213+
) -> anyhow::Result<Self> {
173214
/// TODO: what's the NodeStage timeout?
174215
const REST_TIMEOUT: Duration = Duration::from_secs(10);
175216

176217
let url = clients::tower::Url::parse(endpoint)
177218
.map_err(|error| anyhow!("Invalid API endpoint URL {endpoint}: {error:?}"))?;
219+
let cert = match ca_certificate_path {
220+
Some(path) => {
221+
let cert = std::fs::read(path.clone()).map_err(|error| {
222+
anyhow::anyhow!(
223+
"Failed to create openapi configuration at path {}, Error: '{:?}'",
224+
path.display(),
225+
error
226+
)
227+
})?;
228+
Some(cert)
229+
}
230+
None => None,
231+
};
178232

179-
let config = clients::tower::Configuration::builder()
180-
.with_timeout(REST_TIMEOUT)
181-
.with_concurrency_limit(Some(10))
182-
.build_url(url)
183-
.map_err(|error| {
184-
anyhow::anyhow!("Failed to create openapi configuration, Error: '{error:?}'")
185-
})?;
233+
let config = match (url.scheme(), cert) {
234+
("https", Some(cert)) => clients::tower::Configuration::builder()
235+
.with_timeout(REST_TIMEOUT)
236+
.with_certificate(&cert)
237+
.build_url(url)
238+
.map_err(|error| {
239+
anyhow::anyhow!(
240+
"Failed to create openapi configuration***, Error: '{:?}'",
241+
error
242+
)
243+
})?,
244+
("https", None) => {
245+
anyhow::bail!("HTTPS endpoint requires a CA certificate path");
246+
}
247+
(_, Some(_path)) => {
248+
anyhow::bail!("CA certificate path is only supported for HTTPS endpoints");
249+
}
250+
_ => clients::tower::Configuration::builder()
251+
.with_timeout(REST_TIMEOUT)
252+
.build_url(url)
253+
.map_err(|error| {
254+
anyhow::anyhow!(
255+
"Failed to create openapi configuration, Error???: '{:?}'",
256+
error
257+
)
258+
})?,
259+
};
186260

187261
info!(
188262
"VolumesClient API is initialized with endpoint {endpoint}, request timeout = {REST_TIMEOUT:?}"

control-plane/csi-driver/src/bin/node/main_.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ use std::{
2929
future::Future,
3030
io::ErrorKind,
3131
net::{IpAddr, SocketAddr},
32+
path::PathBuf,
3233
str::FromStr,
3334
};
3435
use tokio::net::UnixListener;
@@ -191,6 +192,13 @@ pub(super) async fn main() -> anyhow::Result<()> {
191192
.default_value("/var/lib/kubelet")
192193
.help("Kubelet path on the host system")
193194
)
195+
.arg(
196+
Arg::new("tls-client-ca-path")
197+
.long("tls-client-ca-path")
198+
.value_parser(clap::value_parser!(PathBuf))
199+
.requires("enable-rest")
200+
.help("path to the CA certificate file")
201+
)
194202
.subcommand(
195203
clap::Command::new("fs-freeze")
196204
.arg(
@@ -345,7 +353,10 @@ pub(super) async fn main() -> anyhow::Result<()> {
345353
}
346354

347355
// Initialize the rest api client.
348-
let client = AppNodesClientWrapper::initialize(matches.get_one::<String>("rest-endpoint"))?;
356+
let client = AppNodesClientWrapper::initialize(
357+
matches.get_one::<String>("rest-endpoint"),
358+
matches.get_one::<PathBuf>("tls-client-ca-path"),
359+
)?;
349360

350361
let registration_enabled = matches.get_flag("enable-registration");
351362

@@ -403,7 +414,10 @@ impl CsiServer {
403414
};
404415

405416
let vol_client = match cli_args.get_one::<String>("rest-endpoint") {
406-
Some(ep) if cli_args.get_flag("enable-rest") => Some(VolumesClientWrapper::new(ep)?),
417+
Some(ep) if cli_args.get_flag("enable-rest") => {
418+
let cert = cli_args.get_one::<PathBuf>("tls-client-ca-path");
419+
Some(VolumesClientWrapper::new(ep, cert.cloned())?)
420+
}
407421
_ => {
408422
tracing::warn!("The rest client is not enabled - functionality may be limited");
409423
None

control-plane/rest/service/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ fn load_certificates<R: std::io::Read>(
185185
.map_err(|_| {
186186
anyhow::anyhow!("Failed to retrieve the rsa private keys from the key file",)
187187
})?;
188+
188189
if keys.is_empty() {
189190
anyhow::bail!("No keys found in the keys file");
190191
}

k8s/operators/src/pool/main.rs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,49 @@ async fn pool_controller(args: ArgMatches) -> anyhow::Result<()> {
129129
.expect("timeout value is invalid")
130130
.into();
131131

132-
let cfg = clients::tower::Configuration::new(url, timeout, None, None, true, None).map_err(
133-
|error| {
132+
let ca_certificate_path: Option<&str> = args
133+
.get_one::<String>("tls-client-ca-path")
134+
.map(|x| x.as_str());
135+
// take in cert path and make pem file
136+
let cert = match ca_certificate_path {
137+
Some(path) => {
138+
let cert = std::fs::read(path).map_err(|error| {
139+
anyhow::anyhow!("Failed to read certificate file, Error: '{:?}'", error)
140+
})?;
141+
Some(cert)
142+
}
143+
None => None,
144+
};
145+
let cfg = match (url.scheme(), cert) {
146+
("https", Some(cert)) => clients::tower::Configuration::new(
147+
url,
148+
timeout,
149+
None,
150+
Some(cert.as_slice()),
151+
true,
152+
None,
153+
)
154+
.map_err(|error| {
134155
anyhow::anyhow!(
135156
"Failed to create openapi configuration, Error: '{:?}'",
136157
error
137158
)
138-
},
139-
)?;
159+
})?,
160+
("https", None) => {
161+
anyhow::bail!("HTTPS endpoint requires a CA certificate path");
162+
}
163+
(_, Some(_path)) => {
164+
anyhow::bail!("CA certificate path is only supported for HTTPS endpoints");
165+
}
166+
_ => clients::tower::Configuration::new(url, timeout, None, None, true, None).map_err(
167+
|error| {
168+
anyhow::anyhow!(
169+
"Failed to create openapi configuration, Error: '{:?}'",
170+
error
171+
)
172+
},
173+
)?,
174+
};
140175
let interval = args
141176
.get_one::<String>("interval")
142177
.unwrap()
@@ -243,6 +278,11 @@ async fn main() -> anyhow::Result<()> {
243278
.value_parser(clap::value_parser!(bool))
244279
.help("Enable ansi color for logs"),
245280
)
281+
.arg(
282+
Arg::new("tls-client-ca-path")
283+
.long("tls-client-ca-path")
284+
.help("path to the CA certificate file"),
285+
)
246286
.get_matches();
247287

248288
utils::print_package_info!();

0 commit comments

Comments
 (0)