diff --git a/CHANGELOG.md b/CHANGELOG.md index bb0203a2..f55d5853 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- The lifetime of auto generated TLS certificates is now configurable with the role and roleGroup + config property `requestedSecretLifetime`. This helps reducing frequent Pod restarts ([#722]). + ### Fixed - Fix OIDC endpoint construction in case the `rootPath` does not have a trailing slash ([#718]). @@ -13,6 +18,7 @@ All notable changes to this project will be documented in this file. [#717]: https://github.com/stackabletech/nifi-operator/pull/717 [#718]: https://github.com/stackabletech/nifi-operator/pull/718 +[#722]: https://github.com/stackabletech/nifi-operator/pull/722 ## [24.11.0] - 2024-11-18 diff --git a/Cargo.lock b/Cargo.lock index a026a399..009b14fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -478,17 +478,6 @@ dependencies = [ "powerfmt", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -1830,9 +1819,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.15" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "log", "once_cell", @@ -2213,15 +2202,15 @@ dependencies = [ [[package]] name = "stackable-operator" -version = "0.82.0" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.82.0#415bbd031bd52e9c0c5392060235030e9930b46b" +version = "0.83.0" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.83.0#3ce7bcbdb58097cde0c0f19488a104c96f69dbc3" dependencies = [ "chrono", "clap", "const_format", "delegate", - "derivative", "dockerfile-parser", + "educe", "either", "futures 0.3.31", "indexmap", @@ -2252,7 +2241,7 @@ dependencies = [ [[package]] name = "stackable-operator-derive" version = "0.3.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.82.0#415bbd031bd52e9c0c5392060235030e9930b46b" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.83.0#3ce7bcbdb58097cde0c0f19488a104c96f69dbc3" dependencies = [ "darling", "proc-macro2", @@ -2263,7 +2252,7 @@ dependencies = [ [[package]] name = "stackable-shared" version = "0.0.1" -source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.82.0#415bbd031bd52e9c0c5392060235030e9930b46b" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.83.0#3ce7bcbdb58097cde0c0f19488a104c96f69dbc3" dependencies = [ "kube", "semver", diff --git a/Cargo.toml b/Cargo.toml index 1d3be928..f07348aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,13 +25,13 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serde_yaml = "0.9" snafu = "0.8" -stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.82.0" } +stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.83.0" } strum = { version = "0.26", features = ["derive"] } tokio = { version = "1.40", features = ["full"] } tracing = "0.1" url = { version = "2.5.2" } xml-rs = "0.8" -# [patch."https://github.com/stackabletech/operator-rs.git"] -# stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" } +#[patch."https://github.com/stackabletech/operator-rs.git"] +#stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" } # stackable-operator = { path = "../operator-rs/crates/stackable-operator" } diff --git a/deploy/helm/nifi-operator/crds/crds.yaml b/deploy/helm/nifi-operator/crds/crds.yaml index a0250f54..b228d736 100644 --- a/deploy/helm/nifi-operator/crds/crds.yaml +++ b/deploy/helm/nifi-operator/crds/crds.yaml @@ -358,6 +358,10 @@ spec: nullable: true type: boolean type: object + requestedSecretLifetime: + description: Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`. Please note that this can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate. + nullable: true + type: string resources: default: cpu: @@ -815,6 +819,10 @@ spec: nullable: true type: boolean type: object + requestedSecretLifetime: + description: Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`. Please note that this can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate. + nullable: true + type: string resources: default: cpu: diff --git a/rust/crd/src/lib.rs b/rust/crd/src/lib.rs index 92a7367c..fe642150 100644 --- a/rust/crd/src/lib.rs +++ b/rust/crd/src/lib.rs @@ -411,10 +411,16 @@ pub struct NifiConfig { /// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. #[fragment_attrs(serde(default))] pub graceful_shutdown_timeout: Option, + + /// Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`. + /// Please note that this can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate. + #[fragment_attrs(serde(default))] + pub requested_secret_lifetime: Option, } impl NifiConfig { - pub const NIFI_SENSITIVE_PROPS_KEY: &'static str = "NIFI_SENSITIVE_PROPS_KEY"; + // Auto TLS certificate lifetime + const DEFAULT_NODE_SECRET_LIFETIME: Duration = Duration::from_days_unchecked(7); pub fn default_config(cluster_name: &str, role: &NifiRole) -> NifiConfigFragment { NifiConfigFragment { @@ -458,6 +464,7 @@ impl NifiConfig { }, affinity: get_affinity(cluster_name, role), graceful_shutdown_timeout: Some(DEFAULT_NODE_GRACEFUL_SHUTDOWN_TIMEOUT), + requested_secret_lifetime: Some(Self::DEFAULT_NODE_SECRET_LIFETIME), } } } diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index c6e3111a..ac80b72a 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -112,6 +112,9 @@ pub struct Ctx { #[strum_discriminants(derive(IntoStaticStr))] #[allow(clippy::enum_variant_names)] pub enum Error { + #[snafu(display("missing secret lifetime"))] + MissingSecretLifetime, + #[snafu(display("NifiCluster object is invalid"))] InvalidNifiCluster { source: error_boundary::InvalidObject, @@ -1253,6 +1256,9 @@ async fn build_node_rolegroup_statefulset( .context(MetadataBuildSnafu)? .build(); + let requested_secret_lifetime = merged_config + .requested_secret_lifetime + .context(MissingSecretLifetimeSnafu)?; let nifi_cluster_name = nifi.name_any(); pod_builder .metadata(metadata) @@ -1301,6 +1307,7 @@ async fn build_node_rolegroup_statefulset( &build_reporting_task_service_name(&nifi_cluster_name), ], SecretFormat::TlsPkcs12, + &requested_secret_lifetime, ) .context(SecuritySnafu)?, ) diff --git a/rust/operator-binary/src/reporting_task/mod.rs b/rust/operator-binary/src/reporting_task/mod.rs index cf32756a..84827f4c 100644 --- a/rust/operator-binary/src/reporting_task/mod.rs +++ b/rust/operator-binary/src/reporting_task/mod.rs @@ -24,10 +24,15 @@ //! use std::collections::BTreeMap; +use crate::security::{ + authentication::{NifiAuthenticationConfig, STACKABLE_ADMIN_USERNAME}, + build_tls_volume, +}; use snafu::{OptionExt, ResultExt, Snafu}; use stackable_nifi_crd::{ NifiCluster, NifiRole, APP_NAME, HTTPS_PORT, HTTPS_PORT_NAME, METRICS_PORT, }; +use stackable_operator::time::Duration; use stackable_operator::{ builder::{ self, @@ -50,11 +55,6 @@ use stackable_operator::{ utils::cluster_info::KubernetesClusterInfo, }; -use crate::security::{ - authentication::{NifiAuthenticationConfig, STACKABLE_ADMIN_USERNAME}, - build_tls_volume, -}; - use super::controller::{build_recommended_labels, NIFI_UID}; const REPORTING_TASK_CERT_VOLUME_NAME: &str = "tls"; @@ -359,6 +359,10 @@ fn build_reporting_task_job( REPORTING_TASK_CERT_VOLUME_NAME, vec![], SecretFormat::TlsPem, + // The certificate is only used for the REST API call, so a short lifetime is sufficient. + // There is no correct way to configure this job since it's an implementation detail. + // Also it will be dropped when support for 1.x is removed. + &Duration::from_days_unchecked(1), ) .context(SecretVolumeBuildFailureSnafu)?, ) diff --git a/rust/operator-binary/src/security/mod.rs b/rust/operator-binary/src/security/mod.rs index 11090bd7..ce473170 100644 --- a/rust/operator-binary/src/security/mod.rs +++ b/rust/operator-binary/src/security/mod.rs @@ -1,6 +1,7 @@ use snafu::{ResultExt, Snafu}; use stackable_nifi_crd::NifiCluster; use stackable_operator::client::Client; +use stackable_operator::time::Duration; use stackable_operator::{builder::pod::volume::SecretFormat, k8s_openapi::api::core::v1::Volume}; pub mod authentication; @@ -42,6 +43,14 @@ pub fn build_tls_volume( volume_name: &str, service_scopes: Vec<&str>, secret_format: SecretFormat, + requested_secret_lifetime: &Duration, ) -> Result { - tls::build_tls_volume(nifi, volume_name, service_scopes, secret_format).context(TlsSnafu) + tls::build_tls_volume( + nifi, + volume_name, + service_scopes, + secret_format, + requested_secret_lifetime, + ) + .context(TlsSnafu) } diff --git a/rust/operator-binary/src/security/tls.rs b/rust/operator-binary/src/security/tls.rs index 070241bb..3cbae6d3 100644 --- a/rust/operator-binary/src/security/tls.rs +++ b/rust/operator-binary/src/security/tls.rs @@ -1,12 +1,12 @@ +use crate::security::authentication::STACKABLE_TLS_STORE_PASSWORD; use snafu::{ResultExt, Snafu}; use stackable_nifi_crd::NifiCluster; +use stackable_operator::time::Duration; use stackable_operator::{ builder::pod::volume::{SecretFormat, SecretOperatorVolumeSourceBuilder, VolumeBuilder}, k8s_openapi::api::core::v1::Volume, }; -use crate::security::authentication::STACKABLE_TLS_STORE_PASSWORD; - pub const KEYSTORE_VOLUME_NAME: &str = "keystore"; pub const KEYSTORE_NIFI_CONTAINER_MOUNT: &str = "/stackable/keystore"; pub const TRUSTSTORE_VOLUME_NAME: &str = "truststore"; @@ -26,6 +26,7 @@ pub(crate) fn build_tls_volume( volume_name: &str, service_scopes: Vec<&str>, secret_format: SecretFormat, + requested_secret_lifetime: &Duration, ) -> Result { let mut secret_volume_source_builder = SecretOperatorVolumeSourceBuilder::new(nifi.server_tls_secret_class()); @@ -44,6 +45,7 @@ pub(crate) fn build_tls_volume( .with_node_scope() .with_pod_scope() .with_format(secret_format) + .with_auto_tls_cert_lifetime(*requested_secret_lifetime) .build() .context(TlsCertSecretClassVolumeBuildSnafu)?, )