Skip to content

Commit 8a68412

Browse files
committed
fix: Manage OIDC admin password secret via cluster_resources
1 parent 6a2415c commit 8a68412

3 files changed

Lines changed: 69 additions & 43 deletions

File tree

rust/operator-binary/src/controller.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ use crate::{
106106
NifiAuthenticationConfig, STACKABLE_SERVER_TLS_DIR, STACKABLE_TLS_STORE_PASSWORD,
107107
},
108108
authorization::{self, OPA_TLS_MOUNT_PATH, ResolvedNifiAuthorizationConfig},
109-
build_tls_volume, check_or_generate_oidc_admin_password, check_or_generate_sensitive_key,
109+
build_oidc_admin_password_secret, build_tls_volume, check_or_generate_sensitive_key,
110110
tls::{KEYSTORE_NIFI_CONTAINER_MOUNT, KEYSTORE_VOLUME_NAME, TRUSTSTORE_VOLUME_NAME},
111111
},
112112
service::{build_rolegroup_headless_service, build_rolegroup_metrics_service},
@@ -241,6 +241,11 @@ pub enum Error {
241241
cm_name: String,
242242
},
243243

244+
#[snafu(display("failed to apply OIDC admin password secret"))]
245+
ApplyOidcAdminPasswordSecret {
246+
source: stackable_operator::cluster_resources::Error,
247+
},
248+
244249
#[snafu(display("failed to patch service account"))]
245250
ApplyServiceAccount {
246251
source: stackable_operator::cluster_resources::Error,
@@ -443,10 +448,23 @@ pub async fn reconcile_nifi(
443448
)
444449
.context(InvalidNifiAuthenticationConfigSnafu)?;
445450

446-
if let NifiAuthenticationConfig::Oidc { .. } = authentication_config {
447-
check_or_generate_oidc_admin_password(client, nifi)
451+
if let NifiAuthenticationConfig::Oidc { .. } = &authentication_config {
452+
let oidc_admin_password_secret = build_oidc_admin_password_secret(
453+
client,
454+
nifi,
455+
build_recommended_labels(
456+
nifi,
457+
&resolved_product_image.app_version_label_value,
458+
"node",
459+
"oidc",
460+
),
461+
)
462+
.await
463+
.context(SecuritySnafu)?;
464+
cluster_resources
465+
.add(client, oidc_admin_password_secret)
448466
.await
449-
.context(SecuritySnafu)?;
467+
.context(ApplyOidcAdminPasswordSecretSnafu)?;
450468
}
451469

452470
let authorization_config = ResolvedNifiAuthorizationConfig::from(

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,12 @@ pub async fn check_or_generate_sensitive_key(
3535
.context(SensitiveKeySnafu)
3636
}
3737

38-
pub async fn check_or_generate_oidc_admin_password(
38+
pub async fn build_oidc_admin_password_secret(
3939
client: &Client,
4040
nifi: &v1alpha1::NifiCluster,
41-
) -> Result<bool> {
42-
oidc::check_or_generate_oidc_admin_password(client, nifi)
41+
labels: stackable_operator::kvp::ObjectLabels<'_, v1alpha1::NifiCluster>,
42+
) -> Result<stackable_operator::k8s_openapi::api::core::v1::Secret> {
43+
oidc::build_oidc_admin_password_secret(client, nifi, labels)
4344
.await
4445
.context(OidcAdminPasswordSnafu)
4546
}

rust/operator-binary/src/security/oidc.rs

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use stackable_operator::{
99
crd::authentication::oidc,
1010
k8s_openapi::api::core::v1::Secret,
1111
kube::{ResourceExt, runtime::reflector::ObjectRef},
12+
kvp::ObjectLabels,
1213
};
1314

1415
use crate::{crd::v1alpha1, security::authentication::STACKABLE_ADMIN_USERNAME};
@@ -37,64 +38,70 @@ pub enum Error {
3738

3839
#[snafu(display("Nifi doesn't support skipping the OIDC TLS verification"))]
3940
SkippingTlsVerificationNotSupported {},
41+
42+
#[snafu(display("failed to build OIDC admin password secret metadata"))]
43+
BuildOidcAdminPasswordSecretMetadata {
44+
source: stackable_operator::builder::meta::Error,
45+
},
4046
}
4147

42-
/// Generate a secret containing the password for the admin user that can access the API.
48+
/// Build a Secret containing the OIDC admin password.
4349
///
44-
/// This admin user is the same as for SingleUser authentication.
45-
pub(crate) async fn check_or_generate_oidc_admin_password(
50+
/// If the secret already exists, the existing password is preserved.
51+
/// Otherwise a new random password is generated.
52+
pub(crate) async fn build_oidc_admin_password_secret(
4653
client: &Client,
4754
nifi: &v1alpha1::NifiCluster,
48-
) -> Result<bool, Error> {
55+
labels: ObjectLabels<'_, v1alpha1::NifiCluster>,
56+
) -> Result<Secret, Error> {
4957
let namespace: &str = &nifi.namespace().context(ObjectHasNoNamespaceSnafu)?;
5058
tracing::debug!("Checking for OIDC admin password configuration");
51-
match client
59+
60+
let password = match client
5261
.get_opt::<Secret>(&build_oidc_admin_password_secret_name(nifi), namespace)
5362
.await
5463
.context(OidcAdminPasswordSecretSnafu)?
5564
{
5665
Some(secret) => {
57-
let admin_password_present = secret
66+
let existing_password = secret
5867
.data
59-
.iter()
60-
.flat_map(|data| data.keys())
61-
.any(|key| key == STACKABLE_ADMIN_USERNAME);
62-
63-
if admin_password_present {
64-
Ok(false)
65-
} else {
66-
MissingAdminPasswordKeySnafu {
68+
.as_ref()
69+
.and_then(|data| data.get(STACKABLE_ADMIN_USERNAME))
70+
.map(|bytes| String::from_utf8_lossy(&bytes.0).into_owned());
71+
72+
match existing_password {
73+
Some(password) => password,
74+
None => MissingAdminPasswordKeySnafu {
6775
secret: ObjectRef::from_obj(&secret),
6876
}
69-
.fail()?
77+
.fail()?,
7078
}
7179
}
7280
None => {
73-
tracing::info!("No existing oidc admin password secret found, generating new one");
74-
let password: String = rand::rng()
81+
tracing::info!("No existing OIDC admin password secret found, generating new one");
82+
rand::rng()
7583
.sample_iter(&Alphanumeric)
7684
.take(15)
7785
.map(char::from)
78-
.collect();
79-
80-
let mut secret_data = BTreeMap::new();
81-
secret_data.insert("admin".to_string(), password);
82-
83-
let new_secret = Secret {
84-
metadata: ObjectMetaBuilder::new()
85-
.namespace(namespace)
86-
.name(build_oidc_admin_password_secret_name(nifi))
87-
.build(),
88-
string_data: Some(secret_data),
89-
..Secret::default()
90-
};
91-
client
92-
.create(&new_secret)
93-
.await
94-
.context(OidcAdminPasswordSecretSnafu)?;
95-
Ok(true)
86+
.collect()
9687
}
97-
}
88+
};
89+
90+
Ok(Secret {
91+
metadata: ObjectMetaBuilder::new()
92+
.name_and_namespace(nifi)
93+
.name(build_oidc_admin_password_secret_name(nifi))
94+
.ownerreference_from_resource(nifi, None, Some(true))
95+
.context(BuildOidcAdminPasswordSecretMetadataSnafu)?
96+
.with_recommended_labels(labels)
97+
.context(BuildOidcAdminPasswordSecretMetadataSnafu)?
98+
.build(),
99+
string_data: Some(BTreeMap::from([(
100+
STACKABLE_ADMIN_USERNAME.to_string(),
101+
password,
102+
)])),
103+
..Secret::default()
104+
})
98105
}
99106

100107
pub fn build_oidc_admin_password_secret_name(nifi: &v1alpha1::NifiCluster) -> String {

0 commit comments

Comments
 (0)