Skip to content

Commit c88a30a

Browse files
authored
feat: Support setting TLS certificate lifetimes (#796)
* feat: Support setting TLS certificate lifetimes * chore: bump op-rs * cargo update -p rustls
1 parent f57aa17 commit c88a30a

File tree

7 files changed

+70
-35
lines changed

7 files changed

+70
-35
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ All notable changes to this project will be documented in this file.
44

55
## [Unreleased]
66

7+
### Added
8+
9+
- The lifetime of auto generated TLS certificates is now configurable with the role and roleGroup
10+
config property `requestedSecretLifetime`. This helps reduce frequent Pod restarts ([#796]).
11+
712
### Fixed
813

914
- BREAKING: Use distinct ServiceAccounts for the Stacklets, so that multiple Stacklets can be
1015
deployed in one namespace. Existing Stacklets will use the newly created ServiceAccounts after
1116
restart ([#793]).
1217

1318
[#793]: https://github.com/stackabletech/kafka-operator/pull/793
19+
[#796]: https://github.com/stackabletech/kafka-operator/pull/796
1420

1521
## [24.11.0] - 2024-11-18
1622

Cargo.lock

Lines changed: 7 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@ serde = { version = "1.0", features = ["derive"] }
2222
serde_json = "1.0"
2323
serde_yaml = "0.9"
2424
snafu = "0.8"
25-
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.82.0" }
25+
stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.83.0" }
2626
strum = { version = "0.26", features = ["derive"] }
2727
tokio = { version = "1.40", features = ["full"] }
2828
tracing = "0.1"
2929

30-
# [patch."https://github.com/stackabletech/operator-rs.git"]
30+
#[patch."https://github.com/stackabletech/operator-rs.git"]
3131
# stackable-operator = { path = "../operator-rs/crates/stackable-operator" }
32-
# stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" }
32+
#stackable-operator = { git = "https://github.com/stackabletech//operator-rs.git", branch = "main" }

deploy/helm/kafka-operator/crds/crds.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,10 @@ spec:
163163
nullable: true
164164
type: boolean
165165
type: object
166+
requestedSecretLifetime:
167+
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.
168+
nullable: true
169+
type: string
166170
resources:
167171
default:
168172
cpu:
@@ -434,6 +438,10 @@ spec:
434438
nullable: true
435439
type: boolean
436440
type: object
441+
requestedSecretLifetime:
442+
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.
443+
nullable: true
444+
type: string
437445
resources:
438446
default:
439447
cpu:

rust/crd/src/lib.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,9 +430,17 @@ pub struct KafkaConfig {
430430

431431
/// The ListenerClass used for connecting to brokers. Should use a direct connection ListenerClass to minimize cost and minimize performance overhead (such as `cluster-internal` or `external-unstable`).
432432
pub broker_listener_class: String,
433+
434+
/// Request secret (currently only autoTls certificates) lifetime from the secret operator, e.g. `7d`, or `30d`.
435+
/// Please note that this can be shortened by the `maxCertificateLifetime` setting on the SecretClass issuing the TLS certificate.
436+
#[fragment_attrs(serde(default))]
437+
pub requested_secret_lifetime: Option<Duration>,
433438
}
434439

435440
impl KafkaConfig {
441+
// Auto TLS certificate lifetime
442+
const DEFAULT_BROKER_SECRET_LIFETIME: Duration = Duration::from_days_unchecked(7);
443+
436444
pub fn default_config(cluster_name: &str, role: &KafkaRole) -> KafkaConfigFragment {
437445
KafkaConfigFragment {
438446
logging: product_logging::spec::default_logging(),
@@ -457,6 +465,7 @@ impl KafkaConfig {
457465
graceful_shutdown_timeout: Some(DEFAULT_BROKER_GRACEFUL_SHUTDOWN_TIMEOUT),
458466
bootstrap_listener_class: Some("cluster-internal".to_string()),
459467
broker_listener_class: Some("cluster-internal".to_string()),
468+
requested_secret_lifetime: Some(Self::DEFAULT_BROKER_SECRET_LIFETIME),
460469
}
461470
}
462471
}

rust/crd/src/security.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,20 @@
66
//! This is required due to overlaps between TLS encryption and e.g. mTLS authentication or Kerberos
77
use std::collections::BTreeMap;
88

9+
use crate::{
10+
authentication::{self, ResolvedAuthenticationClasses},
11+
listener::{self, KafkaListenerConfig},
12+
tls, KafkaCluster, LISTENER_BOOTSTRAP_VOLUME_NAME, SERVER_PROPERTIES_FILE,
13+
STACKABLE_CONFIG_DIR,
14+
};
15+
use crate::{
16+
listener::node_address_cmd, STACKABLE_KERBEROS_KRB5_PATH, STACKABLE_LISTENER_BOOTSTRAP_DIR,
17+
STACKABLE_LISTENER_BROKER_DIR,
18+
};
19+
use crate::{KafkaRole, LISTENER_BROKER_VOLUME_NAME, STACKABLE_LOG_DIR};
920
use indoc::formatdoc;
1021
use snafu::{ensure, ResultExt, Snafu};
22+
use stackable_operator::time::Duration;
1123
use stackable_operator::{
1224
builder::{
1325
self,
@@ -26,18 +38,6 @@ use stackable_operator::{
2638
utils::COMMON_BASH_TRAP_FUNCTIONS,
2739
};
2840

29-
use crate::{
30-
authentication::{self, ResolvedAuthenticationClasses},
31-
listener::{self, KafkaListenerConfig},
32-
tls, KafkaCluster, LISTENER_BOOTSTRAP_VOLUME_NAME, SERVER_PROPERTIES_FILE,
33-
STACKABLE_CONFIG_DIR,
34-
};
35-
use crate::{
36-
listener::node_address_cmd, STACKABLE_KERBEROS_KRB5_PATH, STACKABLE_LISTENER_BOOTSTRAP_DIR,
37-
STACKABLE_LISTENER_BROKER_DIR,
38-
};
39-
use crate::{KafkaRole, LISTENER_BROKER_VOLUME_NAME, STACKABLE_LOG_DIR};
40-
4141
#[derive(Snafu, Debug)]
4242
pub enum Error {
4343
#[snafu(display("failed to process authentication class"))]
@@ -385,6 +385,7 @@ impl KafkaTlsSecurity {
385385
pod_builder: &mut PodBuilder,
386386
cb_kcat_prober: &mut ContainerBuilder,
387387
cb_kafka: &mut ContainerBuilder,
388+
requested_secret_lifetime: &Duration,
388389
) -> Result<(), Error> {
389390
// add tls (server or client authentication volumes) if required
390391
if let Some(tls_server_secret_class) = self.get_tls_secret_class() {
@@ -393,6 +394,7 @@ impl KafkaTlsSecurity {
393394
.add_volume(Self::create_kcat_tls_volume(
394395
Self::STACKABLE_TLS_KCAT_VOLUME_NAME,
395396
tls_server_secret_class,
397+
requested_secret_lifetime,
396398
)?)
397399
.context(AddVolumeSnafu)?;
398400
cb_kcat_prober
@@ -406,6 +408,7 @@ impl KafkaTlsSecurity {
406408
.add_volume(Self::create_tls_keystore_volume(
407409
Self::STACKABLE_TLS_KAFKA_SERVER_VOLUME_NAME,
408410
tls_server_secret_class,
411+
requested_secret_lifetime,
409412
)?)
410413
.context(AddVolumeSnafu)?;
411414
cb_kafka
@@ -421,6 +424,7 @@ impl KafkaTlsSecurity {
421424
.add_volume(Self::create_tls_keystore_volume(
422425
Self::STACKABLE_TLS_KAFKA_INTERNAL_VOLUME_NAME,
423426
tls_internal_secret_class,
427+
requested_secret_lifetime,
424428
)?)
425429
.context(AddVolumeSnafu)?;
426430
cb_kafka
@@ -594,12 +598,17 @@ impl KafkaTlsSecurity {
594598
}
595599

596600
/// Creates ephemeral volumes to mount the `SecretClass` into the Pods for kcat client
597-
fn create_kcat_tls_volume(volume_name: &str, secret_class_name: &str) -> Result<Volume, Error> {
601+
fn create_kcat_tls_volume(
602+
volume_name: &str,
603+
secret_class_name: &str,
604+
requested_secret_lifetime: &Duration,
605+
) -> Result<Volume, Error> {
598606
Ok(VolumeBuilder::new(volume_name)
599607
.ephemeral(
600608
SecretOperatorVolumeSourceBuilder::new(secret_class_name)
601609
.with_pod_scope()
602610
.with_format(SecretFormat::TlsPem)
611+
.with_auto_tls_cert_lifetime(*requested_secret_lifetime)
603612
.build()
604613
.context(SecretVolumeBuildSnafu)?,
605614
)
@@ -610,6 +619,7 @@ impl KafkaTlsSecurity {
610619
fn create_tls_keystore_volume(
611620
volume_name: &str,
612621
secret_class_name: &str,
622+
requested_secret_lifetime: &Duration,
613623
) -> Result<Volume, Error> {
614624
Ok(VolumeBuilder::new(volume_name)
615625
.ephemeral(
@@ -618,6 +628,7 @@ impl KafkaTlsSecurity {
618628
.with_listener_volume_scope(LISTENER_BROKER_VOLUME_NAME)
619629
.with_listener_volume_scope(LISTENER_BOOTSTRAP_VOLUME_NAME)
620630
.with_format(SecretFormat::TlsPkcs12)
631+
.with_auto_tls_cert_lifetime(*requested_secret_lifetime)
621632
.build()
622633
.context(SecretVolumeBuildSnafu)?,
623634
)

rust/operator-binary/src/kafka_controller.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ pub struct Ctx {
110110
#[strum_discriminants(derive(IntoStaticStr))]
111111
#[allow(clippy::enum_variant_names)]
112112
pub enum Error {
113+
#[snafu(display("missing secret lifetime"))]
114+
MissingSecretLifetime,
115+
113116
#[snafu(display("object has no name"))]
114117
ObjectHasNoName,
115118

@@ -363,6 +366,7 @@ impl ReconcilerError for Error {
363366

364367
fn secondary_object(&self) -> Option<ObjectRef<DynamicObject>> {
365368
match self {
369+
Error::MissingSecretLifetime => None,
366370
Error::ObjectHasNoName => None,
367371
Error::ObjectHasNoNamespace => None,
368372
Error::NoBrokerRole => None,
@@ -866,8 +870,16 @@ fn build_broker_rolegroup_statefulset(
866870
let mut pod_builder = PodBuilder::new();
867871

868872
// Add TLS related volumes and volume mounts
873+
let requested_secret_lifetime = merged_config
874+
.requested_secret_lifetime
875+
.context(MissingSecretLifetimeSnafu)?;
869876
kafka_security
870-
.add_volume_and_volume_mounts(&mut pod_builder, &mut cb_kcat_prober, &mut cb_kafka)
877+
.add_volume_and_volume_mounts(
878+
&mut pod_builder,
879+
&mut cb_kcat_prober,
880+
&mut cb_kafka,
881+
&requested_secret_lifetime,
882+
)
871883
.context(AddVolumesAndVolumeMountsSnafu)?;
872884

873885
let mut pvcs = merged_config.resources.storage.build_pvcs();

0 commit comments

Comments
 (0)