Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
e9e527f
test: Add security-config integration test
siegfriedweber Feb 5, 2026
419447c
feat: Add securityConfig to the CRD; Deploy the initial security conf…
siegfriedweber Feb 9, 2026
d12a691
Deploy security config files only if completely managed by the API
siegfriedweber Feb 10, 2026
a0382d0
test(smoke): Use securityConfig
siegfriedweber Feb 10, 2026
0b8ab8a
Deploy security config files only to the managing role group
siegfriedweber Feb 11, 2026
dce4c40
Create admin certificate in init container
siegfriedweber Feb 11, 2026
f6387a9
Add update-security-config container
siegfriedweber Feb 11, 2026
fefcfdb
Configure DN of the admin certificate
siegfriedweber Feb 11, 2026
5aa8f8b
Allow only one pod to manage the security configuration
siegfriedweber Feb 12, 2026
d9e4787
Validate the security configuration; Fix all unit tests
siegfriedweber Feb 12, 2026
5d5cf8a
Allow to disable the security plugin
siegfriedweber Feb 13, 2026
96745ee
Use a structure for the validated security configuration
siegfriedweber Feb 13, 2026
b2c611d
Declare security init containers
siegfriedweber Feb 13, 2026
88cb259
test(backup-restore): Use securityConfig
siegfriedweber Feb 18, 2026
c3d403e
test(external-access): Use securityConfig
siegfriedweber Feb 18, 2026
0d31398
test(ldap): Use securityConfig
siegfriedweber Feb 18, 2026
a8c71c2
test(logging): Use securityConfig
siegfriedweber Feb 18, 2026
dbd5eae
test(metrics): Use securityConfig
siegfriedweber Feb 18, 2026
ad31980
test(opensearch-dashboards): Use securityConfig
siegfriedweber Feb 19, 2026
1b4e332
Rename clusterConfig.security.config to clusterConfig.security.settin…
siegfriedweber Feb 19, 2026
6530f2d
Merge branch 'main' into feat/security-config
siegfriedweber Feb 19, 2026
fd55eda
Update the CRD documentation
siegfriedweber Feb 19, 2026
f78b37f
Rename admin_dn() to super_admin_dn()
siegfriedweber Feb 19, 2026
732b082
Do not use overrides to determine if TLS is enabled
siegfriedweber Feb 19, 2026
7b2bb04
Delete unit tests for removed functions
siegfriedweber Feb 19, 2026
01c34dc
Update changelog
siegfriedweber Feb 19, 2026
1e119a0
Fix shellcheck warnings
siegfriedweber Feb 19, 2026
62548be
Extend node_config unit test
siegfriedweber Feb 19, 2026
1742f57
Rename ValidatedSecurity::config to settings
siegfriedweber Feb 19, 2026
771bd5b
Restructure role group builder
siegfriedweber Feb 20, 2026
63fbded
Move init-keystore script into separate file
siegfriedweber Feb 20, 2026
87585ae
Add security modes to the role group builder
siegfriedweber Feb 20, 2026
f5de51d
test(smoke): Fix assertion
siegfriedweber Feb 23, 2026
f8dcd33
test: Test role group security modes
siegfriedweber Feb 23, 2026
6e0c459
Regenerate charts
siegfriedweber Feb 24, 2026
ee78b3f
Rework RoleGroupSecurityMode
siegfriedweber Feb 25, 2026
7a1fbda
Test NodeConfig::super_admin_dn
siegfriedweber Feb 25, 2026
99bb124
Remove redundant enum SecurityConfigFileType
siegfriedweber Feb 25, 2026
fe86178
Fix comments
siegfriedweber Feb 26, 2026
e94a82d
Test RoleGroupBuilder::security_settings_file_type_managed_by_env_var
siegfriedweber Feb 26, 2026
4b67f0e
Add ValidatedSecurity::Disabled
siegfriedweber Feb 26, 2026
c8d4e81
Test the preprocess step
siegfriedweber Feb 26, 2026
521ca8d
Rename security_config_managing_role_group to security_config_managin…
siegfriedweber Feb 26, 2026
03de85b
Upgrade opensearch-py to version 3.1.0
siegfriedweber Feb 26, 2026
e517f53
Fix tests
siegfriedweber Feb 26, 2026
db0d856
Merge branch 'main' into feat/security-config
siegfriedweber Feb 26, 2026
7e987a3
Fix the test cases that work with the original image
siegfriedweber Feb 26, 2026
8397acc
Add support for DEPRECATION log level
siegfriedweber Feb 27, 2026
540c373
test: Set backoffLimit for all jobs
siegfriedweber Feb 27, 2026
4323261
Merge branch 'main' into feat/security-config
siegfriedweber Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file.
- Configuration parameter `spec.nodes.roleGroups.<role-group-name>.config.discoveryServiceExposed`
added to expose a role-group via the discovery service.
- Add support for OpenSearch 3.4.0 ([#108]).
- Allow the configuration of the OpenSearch security plugin ([#117]).

### Changed

Expand All @@ -49,6 +50,7 @@ All notable changes to this project will be documented in this file.
[#108]: https://github.com/stackabletech/opensearch-operator/pull/108
[#110]: https://github.com/stackabletech/opensearch-operator/pull/110
[#114]: https://github.com/stackabletech/opensearch-operator/pull/114
[#117]: https://github.com/stackabletech/opensearch-operator/pull/117

## [25.11.0] - 2025-11-07

Expand Down
1,054 changes: 1,053 additions & 1 deletion extra/crds.yaml

Large diffs are not rendered by default.

96 changes: 76 additions & 20 deletions rust/operator-binary/src/controller.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,15 @@ use update_status::update_status;
use validate::validate;

use crate::{
controller::preprocess::preprocess,
crd::{NodeRoles, v1alpha1},
framework::{
HasName, HasUid, NameIsValidLabelValue,
product_logging::framework::{ValidatedContainerLogConfigChoice, VectorContainerLogConfig},
role_utils::{GenericProductSpecificCommonConfig, RoleGroupConfig},
types::{
common::Port,
kubernetes::{Hostname, ListenerClassName, NamespaceName, Uid},
kubernetes::{Hostname, ListenerClassName, NamespaceName, SecretClassName, Uid},
operator::{
ClusterName, ControllerName, OperatorName, ProductName, ProductVersion,
RoleGroupName, RoleName,
Expand All @@ -50,6 +51,7 @@ use crate::{
mod apply;
mod build;
mod dereference;
mod preprocess;
mod update_status;
mod validate;

Expand Down Expand Up @@ -176,6 +178,28 @@ impl ValidatedLogging {
}
}

/// Validated security configuration
#[derive(Clone, Debug, PartialEq)]
pub enum ValidatedSecurity {
/// At least one security setting is managed by the operator
ManagedByOperator {
managing_role_group: RoleGroupName,
settings: v1alpha1::SecuritySettings,
tls_server_secret_class: SecretClassName,
tls_internal_secret_class: SecretClassName,
},

/// All security settings are managed by the API
ManagedByApi {
settings: v1alpha1::SecuritySettings,
tls_server_secret_class: Option<SecretClassName>,
tls_internal_secret_class: SecretClassName,
},

/// The OpenSearch security plugin is disabled.
Disabled,
}

#[derive(Clone, Debug, PartialEq)]
pub struct ValidatedDiscoveryEndpoint {
pub hostname: Hostname,
Expand All @@ -200,7 +224,7 @@ pub struct ValidatedCluster {
pub uid: Uid,
pub role_config: v1alpha1::OpenSearchRoleConfig,
pub role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,
pub tls_config: v1alpha1::OpenSearchTls,
pub security: ValidatedSecurity,
pub keystores: Vec<v1alpha1::OpenSearchKeystore>,
pub discovery_endpoint: Option<ValidatedDiscoveryEndpoint>,
}
Expand All @@ -215,7 +239,7 @@ impl ValidatedCluster {
uid: impl Into<Uid>,
role_config: v1alpha1::OpenSearchRoleConfig,
role_group_configs: BTreeMap<RoleGroupName, OpenSearchRoleGroupConfig>,
tls_config: v1alpha1::OpenSearchTls,
security: ValidatedSecurity,
keystores: Vec<v1alpha1::OpenSearchKeystore>,
discovery_endpoint: Option<ValidatedDiscoveryEndpoint>,
) -> Self {
Expand All @@ -234,7 +258,7 @@ impl ValidatedCluster {
uid,
role_config,
role_group_configs,
tls_config,
security,
keystores,
discovery_endpoint,
}
Expand Down Expand Up @@ -269,6 +293,20 @@ impl ValidatedCluster {
.filter(|c| c.1.config.node_roles.contains(node_role))
.collect()
}

/// Whether security is enabled and a server TLS class is defined or not.
pub fn is_server_tls_enabled(&self) -> bool {
matches!(
self.security,
ValidatedSecurity::ManagedByApi {
tls_server_secret_class: Some(_),
..
} | ValidatedSecurity::ManagedByOperator {
tls_server_secret_class: _,
..
}
)
}
}

impl HasName for ValidatedCluster {
Expand Down Expand Up @@ -355,10 +393,14 @@ pub fn error_policy(
/// Reconcile function of the OpenSearchCluster controller
///
/// The reconcile function performs the following steps:
/// 1. Validate the given cluster specification and return a [`ValidatedCluster`] if successful.
/// 2. Build Kubernetes resource specifications from the validated cluster.
/// 3. Apply the Kubernetes resource specifications
/// 4. Update the cluster status
/// 1. Dereference objects which are referenced in the OpenSearchCluster.
/// 2. Preprocess the OpenSearchCluster specification and add configurations that the user is
/// allowed to leave out.
/// 3. Validate the preprocessed cluster specification and the dereferenced objects and return a
/// [`ValidatedCluster`] if successful.
/// 4. Build Kubernetes resource specifications from the validated cluster.
/// 5. Apply the Kubernetes resource specifications
/// 6. Update the cluster status
pub async fn reconcile(
object: Arc<DeserializeGuard<v1alpha1::OpenSearchCluster>>,
context: Arc<Context>,
Expand All @@ -369,30 +411,35 @@ pub async fn reconcile(
.0
.as_ref()
.map_err(stackable_operator::kube::core::error_boundary::InvalidObject::clone)
.context(DeserializeClusterDefinitionSnafu)?;
.context(DeserializeClusterDefinitionSnafu)?
.clone();

// dereference (client required)
let dereferenced_objects = dereference(&context.client, cluster)
let dereferenced_objects = dereference(&context.client, &cluster)
.await
.context(DereferenceSnafu)?;

// preprocess (no client required)
let preprocessed_cluster = preprocess(cluster);

// validate (no client required)
let validated_cluster =
validate(&context.names, cluster, &dereferenced_objects).context(ValidateClusterSnafu)?;
let validated_cluster = validate(&context.names, &preprocessed_cluster, &dereferenced_objects)
.context(ValidateClusterSnafu)?;

// build (no client required; infallible)
let prepared_resources = build(&context.names, validated_cluster.clone());

// apply (client required)
let apply_strategy = ClusterResourceApplyStrategy::from(&cluster.spec.cluster_operation);
let apply_strategy =
ClusterResourceApplyStrategy::from(&preprocessed_cluster.spec.cluster_operation);
let applied_resources = Applier::new(
&context.client,
&context.names,
&validated_cluster.name,
&validated_cluster.namespace,
&validated_cluster.uid,
apply_strategy,
&cluster.spec.object_overrides,
&preprocessed_cluster.spec.object_overrides,
)
.apply(prepared_resources)
.await
Expand All @@ -401,9 +448,14 @@ pub async fn reconcile(
// not necessary in this controller: create discovery ConfigMap based on the applied resources (client required)

// update status (client required)
update_status(&context.client, &context.names, cluster, applied_resources)
.await
.context(UpdateStatusSnafu)?;
update_status(
&context.client,
&context.names,
&preprocessed_cluster,
applied_resources,
)
.await
.context(UpdateStatusSnafu)?;

Ok(Action::await_change())
}
Expand All @@ -429,14 +481,14 @@ mod tests {

use super::{Context, OpenSearchRoleGroupConfig, ValidatedCluster, ValidatedLogging};
use crate::{
controller::{OpenSearchNodeResources, ValidatedOpenSearchConfig},
controller::{OpenSearchNodeResources, ValidatedOpenSearchConfig, ValidatedSecurity},
crd::{NodeRoles, v1alpha1},
framework::{
builder::pod::container::EnvVarSet,
product_logging::framework::ValidatedContainerLogConfigChoice,
role_utils::GenericProductSpecificCommonConfig,
types::{
kubernetes::{ListenerClassName, NamespaceName},
kubernetes::{ListenerClassName, NamespaceName, SecretClassName},
operator::{ClusterName, OperatorName, ProductVersion, RoleGroupName},
},
},
Expand Down Expand Up @@ -552,7 +604,11 @@ mod tests {
),
]
.into(),
v1alpha1::OpenSearchTls::default(),
ValidatedSecurity::ManagedByApi {
settings: v1alpha1::SecuritySettings::default(),
tls_server_secret_class: None,
tls_internal_secret_class: SecretClassName::from_str_unsafe("tls"),
},
vec![],
None,
)
Expand Down
4 changes: 2 additions & 2 deletions rust/operator-binary/src/controller/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ mod tests {
controller::{
ContextNames, OpenSearchNodeResources, OpenSearchRoleGroupConfig, ValidatedCluster,
ValidatedContainerLogConfigChoice, ValidatedDiscoveryEndpoint, ValidatedLogging,
ValidatedOpenSearchConfig,
ValidatedOpenSearchConfig, ValidatedSecurity,
},
crd::{NodeRoles, v1alpha1},
framework::{
Expand Down Expand Up @@ -209,7 +209,7 @@ mod tests {
),
]
.into(),
v1alpha1::OpenSearchTls::default(),
ValidatedSecurity::Disabled,
vec![],
Some(ValidatedDiscoveryEndpoint {
hostname: Hostname::from_str_unsafe("1.2.3.4"),
Expand Down
Loading