Skip to content

Commit fe1d9ca

Browse files
committed
feat: Add relaxed file loading
1 parent 07c3ad7 commit fe1d9ca

5 files changed

Lines changed: 109 additions & 52 deletions

File tree

rust/operator-binary/src/backend/kerberos_keytab.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ cluster.local = {realm_name}
196196
.cluster.local = {realm_name}
197197
"#
198198
);
199+
199200
let profile_file_path = tmp.path().join("krb5.conf");
200201
{
201202
let mut profile_file = File::create(&profile_file_path)
@@ -216,6 +217,7 @@ cluster.local = {realm_name}
216217
.await
217218
.context(WriteAdminKeytabSnafu)?;
218219
}
220+
219221
let keytab_file_path = tmp.path().join("pod-keytab");
220222
let mut pod_principals: Vec<KerberosPrincipal> = Vec::new();
221223
for service_name in &selector.kerberos_service_names {
@@ -300,7 +302,7 @@ cluster.local = {realm_name}
300302
.context(ReadProvisionedKeytabSnafu)?;
301303
Ok(SecretContents::new(SecretData::WellKnown(
302304
WellKnownSecretData::Kerberos(well_known::Kerberos {
303-
keytab: keytab_data,
305+
keytab: Some(keytab_data),
304306
krb5_conf: profile.into_bytes(),
305307
}),
306308
)))

rust/operator-binary/src/csi_server/node.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ impl SecretProvisionerNode {
220220
selector: SecretVolumeSelector,
221221
) -> Result<(), PublishError> {
222222
let SecretVolumeSelector {
223-
only_provision_identity,
223+
only_provision_identity: relaxed,
224224
format,
225225
compat,
226226
names,
@@ -240,7 +240,7 @@ impl SecretProvisionerNode {
240240

241241
for (k, v) in data
242242
.data
243-
.into_files(format, names, compat, only_provision_identity)
243+
.into_files(format, names, compat, relaxed)
244244
.context(publish_error::FormatDataSnafu)?
245245
{
246246
// The following few lines of code do some basic checks against

rust/operator-binary/src/format/mod.rs

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ pub enum SecretData {
2020
Unknown(SecretFiles),
2121
}
2222
impl SecretData {
23-
pub fn parse(self) -> Result<WellKnownSecretData, ParseError> {
23+
pub fn parse(self, relaxed: bool) -> Result<WellKnownSecretData, ParseError> {
2424
match self {
2525
Self::WellKnown(data) => Ok(data),
26-
Self::Unknown(files) => WellKnownSecretData::from_files(files),
26+
Self::Unknown(files) => WellKnownSecretData::from_files(files, relaxed),
2727
}
2828
}
2929

@@ -32,15 +32,22 @@ impl SecretData {
3232
format: Option<SecretFormat>,
3333
names: NamingOptions,
3434
compat: CompatibilityOptions,
35-
only_identity: bool,
35+
relaxed: bool,
3636
) -> Result<SecretFiles, IntoFilesError> {
3737
let files = if let Some(format) = format {
38-
self.parse()?
38+
tracing::debug!(
39+
?format,
40+
?names,
41+
relaxed,
42+
"Explicit format requested: parsing and converting to transform into files"
43+
);
44+
45+
self.parse(relaxed)?
3946
.convert_to(format, compat)?
40-
.into_files(names, only_identity)
47+
.into_files(names)
4148
} else {
4249
match self {
43-
SecretData::WellKnown(data) => data.into_files(names, only_identity),
50+
SecretData::WellKnown(data) => data.into_files(names),
4451
SecretData::Unknown(files) => files,
4552
}
4653
};

rust/operator-binary/src/format/well_known.rs

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use stackable_operator::schemars::{self, JsonSchema};
44
use strum::EnumDiscriminants;
55

66
use super::{ConvertError, SecretFiles, convert};
7+
use crate::utils::ResultExt;
78

89
const FILE_PEM_CERT_CERT: &str = "tls.crt";
910
const FILE_PEM_CERT_KEY: &str = "tls.key";
@@ -30,7 +31,7 @@ pub struct TlsPkcs12 {
3031

3132
#[derive(Debug)]
3233
pub struct Kerberos {
33-
pub keytab: Vec<u8>,
34+
pub keytab: Option<Vec<u8>>,
3435
pub krb5_conf: Vec<u8>,
3536
}
3637

@@ -47,71 +48,88 @@ pub enum WellKnownSecretData {
4748
}
4849

4950
impl WellKnownSecretData {
50-
pub fn into_files(self, names: NamingOptions, only_identity: bool) -> SecretFiles {
51+
pub fn into_files(self, names: NamingOptions) -> SecretFiles {
5152
match self {
5253
WellKnownSecretData::TlsPem(TlsPem {
5354
certificate_pem,
5455
key_pem,
5556
ca_pem,
56-
}) => {
57-
let mut files = vec![Some((names.tls_pem_ca_name, ca_pem))];
58-
59-
if !only_identity {
60-
files.extend([
61-
Some(names.tls_pem_cert_name).zip(certificate_pem),
62-
Some(names.tls_pem_key_name).zip(key_pem),
63-
]);
64-
}
65-
66-
files.into_iter().flatten().collect()
67-
}
57+
}) => [
58+
Some((names.tls_pem_ca_name, ca_pem)),
59+
Some(names.tls_pem_cert_name).zip(certificate_pem),
60+
Some(names.tls_pem_key_name).zip(key_pem),
61+
]
62+
.into_iter()
63+
.flatten()
64+
.collect(),
6865
WellKnownSecretData::TlsPkcs12(TlsPkcs12 {
6966
keystore,
7067
truststore,
71-
}) => {
72-
let mut files = vec![Some((names.tls_pkcs12_truststore_name, truststore))];
73-
74-
if !only_identity {
75-
files.push(Some(names.tls_pkcs12_keystore_name).zip(keystore));
76-
}
77-
78-
files.into_iter().flatten().collect()
79-
}
80-
WellKnownSecretData::Kerberos(Kerberos { keytab, krb5_conf }) => {
81-
let mut files = vec![(FILE_KERBEROS_KEYTAB_KRB5_CONF.to_string(), krb5_conf)];
82-
83-
if !only_identity {
84-
files.push((FILE_KERBEROS_KEYTAB_KEYTAB.to_string(), keytab));
85-
}
86-
87-
SecretFiles::from_iter(files)
88-
}
68+
}) => [
69+
Some((names.tls_pkcs12_truststore_name, truststore)),
70+
Some(names.tls_pkcs12_keystore_name).zip(keystore),
71+
]
72+
.into_iter()
73+
.flatten()
74+
.collect(),
75+
WellKnownSecretData::Kerberos(Kerberos { keytab, krb5_conf }) => [
76+
Some((FILE_KERBEROS_KEYTAB_KRB5_CONF.to_owned(), krb5_conf)),
77+
Some(FILE_KERBEROS_KEYTAB_KEYTAB.to_owned()).zip(keytab),
78+
]
79+
.into_iter()
80+
.flatten()
81+
.collect(),
8982
}
9083
}
9184

92-
pub fn from_files(mut files: SecretFiles) -> Result<WellKnownSecretData, FromFilesError> {
85+
pub fn from_files(
86+
mut files: SecretFiles,
87+
relaxed: bool,
88+
) -> Result<WellKnownSecretData, FromFilesError> {
89+
tracing::debug!(relaxed, "Constructing well-known secret data from files");
90+
9391
let mut take_file = |format, file| {
9492
files
9593
.remove(file)
9694
.context(from_files_error::MissingRequiredFileSnafu { format, file })
9795
};
9896

99-
if let Ok(certificate_pem) = take_file(SecretFormat::TlsPem, FILE_PEM_CERT_CERT) {
97+
// Which file is tried to be parsed first matters. To support the use-case of people bringing
98+
// their own non-sensitive data via a Secret and consumers only requiring access to
99+
// non-sensitve data (for example for CA verification), the non-senstive files are parsed
100+
// first. If the `relaxed` flag is provided, this function tries to parse sensitive files
101+
// but won't hard-error when they are not found.
102+
103+
if let Ok(ca_pem) = take_file(SecretFormat::TlsPem, FILE_PEM_CERT_CA) {
100104
let mut take_file = |file| take_file(SecretFormat::TlsPem, file);
105+
106+
let certificate_pem = take_file(FILE_PEM_CERT_CERT).ok_if(relaxed)?;
107+
let key_pem = take_file(FILE_PEM_CERT_KEY).ok_if(relaxed)?;
108+
101109
Ok(WellKnownSecretData::TlsPem(TlsPem {
102-
certificate_pem: Some(certificate_pem),
103-
key_pem: Some(take_file(FILE_PEM_CERT_KEY)?),
104-
ca_pem: take_file(FILE_PEM_CERT_CA)?,
110+
certificate_pem,
111+
key_pem,
112+
ca_pem,
105113
}))
106-
} else if let Ok(keystore) = take_file(SecretFormat::TlsPkcs12, FILE_PKCS12_CERT_KEYSTORE) {
114+
} else if let Ok(truststore) =
115+
take_file(SecretFormat::TlsPkcs12, FILE_PKCS12_CERT_TRUSTSTORE)
116+
{
117+
let keystore =
118+
take_file(SecretFormat::TlsPkcs12, FILE_PKCS12_CERT_KEYSTORE).ok_if(relaxed)?;
119+
107120
Ok(WellKnownSecretData::TlsPkcs12(TlsPkcs12 {
108-
keystore: Some(keystore),
109-
truststore: take_file(SecretFormat::TlsPkcs12, FILE_PKCS12_CERT_TRUSTSTORE)?,
121+
keystore,
122+
truststore,
110123
}))
111-
} else if let Ok(keytab) = take_file(SecretFormat::Kerberos, FILE_KERBEROS_KEYTAB_KEYTAB) {
124+
} else if let Ok(krb5_conf) =
125+
take_file(SecretFormat::Kerberos, FILE_KERBEROS_KEYTAB_KRB5_CONF)
126+
{
127+
let keytab =
128+
take_file(SecretFormat::Kerberos, FILE_KERBEROS_KEYTAB_KEYTAB).ok_if(relaxed)?;
129+
112130
Ok(WellKnownSecretData::Kerberos(Kerberos {
113131
keytab,
114-
krb5_conf: take_file(SecretFormat::Kerberos, FILE_KERBEROS_KEYTAB_KRB5_CONF)?,
132+
krb5_conf,
115133
}))
116134
} else {
117135
from_files_error::UnknownFormatSnafu {

rust/operator-binary/src/utils.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,14 +229,32 @@ where
229229
}
230230
}
231231

232+
pub trait ResultExt<T, E> {
233+
/// Transforms this [`Result<T, E>`] into [`Ok(Some(T))`] if [`Ok`], [`Ok(None)`] if [`Err`] and
234+
/// `predicate` is `true` or [`Err(_)`] if [`Err`].
235+
///
236+
/// This basically applies [`Result::ok`] only if `predicate` is `true`.
237+
fn ok_if(self, predicate: bool) -> Result<Option<T>, E>;
238+
}
239+
240+
impl<T, E> ResultExt<T, E> for Result<T, E> {
241+
fn ok_if(self, predicate: bool) -> Result<Option<T>, E> {
242+
match self {
243+
Ok(ok) => Ok(Some(ok)),
244+
Err(_) if predicate => Ok(None),
245+
Err(err) => Err(err),
246+
}
247+
}
248+
}
249+
232250
#[cfg(test)]
233251
mod tests {
234252
use futures::StreamExt;
235253
use openssl::asn1::Asn1Time;
236254
use time::OffsetDateTime;
237255

238256
use super::{asn1time_to_offsetdatetime, iterator_try_concat_bytes};
239-
use crate::utils::{Flattened, FmtByteSlice, error_full_message, trystream_any};
257+
use crate::utils::{Flattened, FmtByteSlice, ResultExt, error_full_message, trystream_any};
240258

241259
#[test]
242260
fn fmt_hex_byte_slice() {
@@ -346,4 +364,16 @@ mod tests {
346364
assert_eq!(small, vec![2, 10, 5]);
347365
assert_eq!(big, vec![1000, 2000]);
348366
}
367+
368+
#[test]
369+
fn ok_if() {
370+
let ok: Result<_, ()> = Ok(42usize);
371+
let err: Result<(), _> = Err(());
372+
373+
assert_eq!(Some(42usize), ok.ok_if(true).expect("must be Ok"));
374+
assert_eq!(Some(42usize), ok.ok_if(false).expect("must be Ok"));
375+
376+
assert_eq!(None, err.ok_if(true).expect("must be Ok"));
377+
assert!(err.ok_if(false).is_err());
378+
}
349379
}

0 commit comments

Comments
 (0)