Skip to content

Commit ebe7226

Browse files
test: Enable hot reloading in password files (#868)
* test: Enable hot reloading in password files * doc: Explain the annotation restarter.stackable.tech/ignore in the security documentation * chore: Update changelog * feat: Add annotations to the StatefulSet to ignore hot-reloadable Secrets * chore: Avoid an unnecessary clone of a data structure
1 parent 63f69c7 commit ebe7226

9 files changed

Lines changed: 61 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ All notable changes to this project will be documented in this file.
2020
This caused problems, as they have been cached by Kubernetes, so re-creations of the mentioned Secrets (e.g. by deleting and re-creating the stacklet)
2121
could cause Trino Pods to have different shared secrets, causing workers failing to join the coordinator.
2222
This fix places the secrets in mutable Kubernetes Secrets going forward and migrates existing immutable Secrets to mutable by re-creating them ([#876]).
23+
- Re-enable hot-reloading of password file Secrets ([#868]).
2324

25+
[#868]: https://github.com/stackabletech/trino-operator/pull/868
2426
[#869]: https://github.com/stackabletech/trino-operator/pull/869
2527
[#876]: https://github.com/stackabletech/trino-operator/pull/876
2628
[#878]: https://github.com/stackabletech/trino-operator/pull/878

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! - volume and volume mounts
88
//! - extra containers and commands
99
//!
10-
use std::collections::{BTreeMap, HashMap};
10+
use std::collections::{BTreeMap, BTreeSet, HashMap};
1111

1212
use snafu::{OptionExt, ResultExt, Snafu};
1313
use stackable_operator::{
@@ -99,6 +99,8 @@ pub struct TrinoAuthenticationConfig {
9999
volume_mounts: HashMap<TrinoRole, BTreeMap<crate::crd::Container, Vec<VolumeMount>>>,
100100
/// Additional side car container for the provided role
101101
sidecar_containers: HashMap<TrinoRole, Vec<Container>>,
102+
/// Secrets which can be hot-reloaded and should be excluded from the restart controller
103+
hot_reloaded_secrets: BTreeSet<String>,
102104
}
103105

104106
impl TrinoAuthenticationConfig {
@@ -368,6 +370,16 @@ impl TrinoAuthenticationConfig {
368370
.unwrap_or_default()
369371
}
370372

373+
/// Retrieve all Secrets which can be hot-reloaded
374+
pub fn hot_reloaded_secrets(&self) -> &BTreeSet<String> {
375+
&self.hot_reloaded_secrets
376+
}
377+
378+
/// Add a Secret which can be hot-reloaded
379+
pub fn add_hot_reloaded_secret(&mut self, secret_name: String) {
380+
self.hot_reloaded_secrets.insert(secret_name);
381+
}
382+
371383
/// This is a helper to easily extend/merge this struct
372384
fn extend(&mut self, other: Self) {
373385
for (role, data) in other.config_properties {
@@ -419,6 +431,8 @@ impl TrinoAuthenticationConfig {
419431
.or_default()
420432
.extend(data)
421433
}
434+
435+
self.hot_reloaded_secrets.extend(other.hot_reloaded_secrets);
422436
}
423437
}
424438

rust/operator-binary/src/authentication/password/file.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,15 @@ impl FileAuthenticator {
6565
config_data
6666
}
6767

68+
/// Return the name of the Secret providing the usernames and passwords
69+
pub fn secret_name(&self) -> String {
70+
self.file.user_credentials_secret.name.clone()
71+
}
72+
6873
/// Build the volume for the user secret
6974
pub fn secret_volume(&self) -> Volume {
7075
VolumeBuilder::new(self.secret_volume_name())
71-
.with_secret(&self.file.user_credentials_secret.name, false)
76+
.with_secret(self.secret_name(), false)
7277
.build()
7378
}
7479

rust/operator-binary/src/authentication/password/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ impl TrinoPasswordAuthentication {
119119
Container::Trino,
120120
FileAuthenticator::password_db_volume_mount(),
121121
);
122+
123+
password_authentication_config
124+
.add_hot_reloaded_secret(file_authenticator.secret_name());
122125
}
123126
TrinoPasswordAuthenticator::Ldap(ldap_authenticator) => {
124127
let config_file_name = ldap_authenticator.config_file_name();

rust/operator-binary/src/controller.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ use stackable_operator::{
5151
core::{DeserializeGuard, error_boundary},
5252
runtime::{controller::Action, reflector::ObjectRef},
5353
},
54-
kvp::{Annotation, Labels, ObjectLabels},
54+
kvp::{Annotation, Annotations, Labels, ObjectLabels},
5555
logging::controller::ReconcilerError,
5656
memory::{BinaryMultiple, MemoryQuantity},
5757
product_config_utils::{
@@ -1381,6 +1381,21 @@ fn build_rolegroup_statefulset(
13811381
pod_template.merge_from(role.config.pod_overrides.clone());
13821382
pod_template.merge_from(rolegroup.config.pod_overrides.clone());
13831383

1384+
let ignore_secret_annotations = trino_authentication_config
1385+
.hot_reloaded_secrets()
1386+
.iter()
1387+
.enumerate()
1388+
.map(|(i, secret_name)| {
1389+
(
1390+
format!("restarter.stackable.tech/ignore-secret.{i}"),
1391+
secret_name,
1392+
)
1393+
})
1394+
.collect::<BTreeMap<_, _>>();
1395+
1396+
let annotations =
1397+
Annotations::try_from(ignore_secret_annotations).context(AnnotationBuildSnafu)?;
1398+
13841399
Ok(StatefulSet {
13851400
metadata: ObjectMetaBuilder::new()
13861401
.name_and_namespace(trino)
@@ -1395,6 +1410,7 @@ fn build_rolegroup_statefulset(
13951410
))
13961411
.context(MetadataBuildSnafu)?
13971412
.with_label(RESTART_CONTROLLER_ENABLED_LABEL.to_owned())
1413+
.with_annotations(annotations)
13981414
.build(),
13991415
spec: Some(StatefulSetSpec {
14001416
pod_management_policy: Some("Parallel".to_string()),

tests/templates/kuttl/authentication/11-create-authentication-classes.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,6 @@ metadata:
55
name: create-ldap-user
66
commands:
77
# We need to replace $NAMESPACE (by KUTTL) in the create-authentication-classes.yaml(.j2)
8-
- script: eval "echo \"$(cat create-authentication-classes.yaml)\"" | kubectl apply -f -
8+
- script: >
9+
envsubst '$NAMESPACE' < create-authentication-classes.yaml |
10+
kubectl apply --filename=-

tests/templates/kuttl/authentication/30-hot-reloading-add-user.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ apiVersion: kuttl.dev/v1beta1
33
kind: TestStep
44
commands:
55
# We need to replace $NAMESPACE (by KUTTL) in the add_user.yaml(.j2)
6-
- script: eval "echo \"$(cat add_user.yaml)\"" | kubectl replace -f -
6+
- script: >
7+
envsubst '$NAMESPACE' < add_user.yaml |
8+
kubectl replace --filename=-

tests/templates/kuttl/authentication/32-hot-reloading-remove-user.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ apiVersion: kuttl.dev/v1beta1
33
kind: TestStep
44
commands:
55
# We need to replace $NAMESPACE (by KUTTL) in the remove_user.yaml(.j2)
6-
- script: eval "echo \"$(cat remove_user.yaml)\"" | kubectl replace -f -
6+
- script: >
7+
envsubst '$NAMESPACE' < remove_user.yaml |
8+
kubectl replace --filename=-

tests/templates/kuttl/authentication/33-assert.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,12 @@ timeout: 600
55
commands:
66
# We use the check-active-workers script for the login. Since we do want to wait until we cannot log in anymore
77
# we flip the return value in the end.
8-
- script: kubectl exec -n $NAMESPACE trino-test-helper-0 -- python /tmp/check-active-workers.py -u hot_reloaded -p hot_reloaded -c trino-coordinator-default-headless.$NAMESPACE.svc.cluster.local -w 1; if [ $? -eq 0 ]; then exit 1; fi
8+
- script: |
9+
set +e
10+
kubectl exec -n $NAMESPACE trino-test-helper-0 -- \
11+
python /tmp/check-active-workers.py -u hot_reloaded -p hot_reloaded -c trino-coordinator-default-headless.$NAMESPACE.svc.cluster.local -w 1
12+
if [ $? -eq 1 ]; then
13+
exit 0
14+
else
15+
exit 1
16+
fi

0 commit comments

Comments
 (0)