Skip to content

Commit

Permalink
feat: Support setting TLS certificate lifetimes (#722)
Browse files Browse the repository at this point in the history
* feat: Support setting TLS certificate lifetimes

* Update CHANGELOG.md

* chore: bump op-rs

* cargo update -p rustls
  • Loading branch information
razvan authored Dec 4, 2024
1 parent 7e78aa2 commit 95def6b
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 30 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]).
Expand All @@ -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

Expand Down
25 changes: 7 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
8 changes: 8 additions & 0 deletions deploy/helm/nifi-operator/crds/crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
9 changes: 8 additions & 1 deletion rust/crd/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Duration>,

/// 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<Duration>,
}

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 {
Expand Down Expand Up @@ -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),
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions rust/operator-binary/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)?,
)
Expand Down
14 changes: 9 additions & 5 deletions rust/operator-binary/src/reporting_task/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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";
Expand Down Expand Up @@ -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)?,
)
Expand Down
11 changes: 10 additions & 1 deletion rust/operator-binary/src/security/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -42,6 +43,14 @@ pub fn build_tls_volume(
volume_name: &str,
service_scopes: Vec<&str>,
secret_format: SecretFormat,
requested_secret_lifetime: &Duration,
) -> Result<Volume> {
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)
}
6 changes: 4 additions & 2 deletions rust/operator-binary/src/security/tls.rs
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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<Volume> {
let mut secret_volume_source_builder =
SecretOperatorVolumeSourceBuilder::new(nifi.server_tls_secret_class());
Expand All @@ -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)?,
)
Expand Down

0 comments on commit 95def6b

Please sign in to comment.